<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
<meta name="viewport"
      content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">

    <meta name="author" content="Ian Tang">


    <meta name="subtitle" content="岁月不居时节如流">


    <meta name="description" content="好记性不如烂笔头">



<title>Neutron学习 | 随笔</title>



    <link rel="icon" href="/image/The_Lion_King_32_32.png">




    <!-- stylesheets list from _config.yml -->
    
    <link rel="stylesheet" href="/css/style.css">
    



    <!-- scripts list from _config.yml -->
    
    <script src="/js/script.js"></script>
    
    <script src="/js/tocbot.min.js"></script>
    



    
    
        
    


<meta name="generator" content="Hexo 6.3.0"></head>

<body>
    <script>
        // this function is used to check current theme before page loaded.
        (() => {
            const currentTheme = window.localStorage && window.localStorage.getItem('theme') || '';
            const isDark = currentTheme === 'dark';
            const pagebody = document.getElementsByTagName('body')[0]
            if (isDark) {
                pagebody.classList.add('dark-theme');
                // mobile
                document.getElementById("mobile-toggle-theme").innerText = "· Dark"
            } else {
                pagebody.classList.remove('dark-theme');
                // mobile
                document.getElementById("mobile-toggle-theme").innerText = "· Light"
            }
        })();
    </script>

    <div class="wrapper">
        <header>
    <nav class="navbar">
        <div class="container">
            <div class="navbar-header header-logo"><a href="/">Tangkaifei&#39;s Blog</a></div>
            <div class="menu navbar-right">
                
                    <a class="menu-item" href="/archives">Posts</a>
                
                    <a class="menu-item" href="/category">Categories</a>
                
                    <a class="menu-item" href="/tag">Tags</a>
                
                    <a class="menu-item" href="/about">About</a>
                
                <input id="switch_default" type="checkbox" class="switch_default">
                <label for="switch_default" class="toggleBtn"></label>
            </div>
        </div>
    </nav>

    
    <nav class="navbar-mobile" id="nav-mobile">
        <div class="container">
            <div class="navbar-header">
                <div>
                    <a href="/">Tangkaifei&#39;s Blog</a><a id="mobile-toggle-theme">·&nbsp;Light</a>
                </div>
                <div class="menu-toggle" onclick="mobileBtn()">&#9776; Menu</div>
            </div>
            <div class="menu" id="mobile-menu">
                
                    <a class="menu-item" href="/archives">Posts</a>
                
                    <a class="menu-item" href="/category">Categories</a>
                
                    <a class="menu-item" href="/tag">Tags</a>
                
                    <a class="menu-item" href="/about">About</a>
                
            </div>
        </div>
    </nav>

</header>
<script>
    var mobileBtn = function f() {
        var toggleMenu = document.getElementsByClassName("menu-toggle")[0];
        var mobileMenu = document.getElementById("mobile-menu");
        if(toggleMenu.classList.contains("active")){
           toggleMenu.classList.remove("active")
            mobileMenu.classList.remove("active")
        }else{
            toggleMenu.classList.add("active")
            mobileMenu.classList.add("active")
        }
    }
</script>
            <div class="main">
                <div class="container">
    
    
        <div class="post-toc">
    <div class="tocbot-list">
    </div>
    <div class="tocbot-list-menu">
        <a class="tocbot-toc-expand" onclick="expand_toc()">Expand all</a>
        <a onclick="go_top()">Back to top</a>
        <a onclick="go_bottom()">Go to bottom</a>
    </div>
</div>

<script>
    var tocbot_timer;
    var DEPTH_MAX = 6; // 为 6 时展开所有
    var tocbot_default_config = {
        tocSelector: '.tocbot-list',
        contentSelector: '.post-content',
        headingSelector: 'h1, h2, h3, h4, h5',
        orderedList: false,
        scrollSmooth: true,
        onClick: extend_click,
    };

    function extend_click() {
        clearTimeout(tocbot_timer);
        tocbot_timer = setTimeout(function() {
            tocbot.refresh(obj_merge(tocbot_default_config, {
                hasInnerContainers: true
            }));
        }, 420); // 这个值是由 tocbot 源码里定义的 scrollSmoothDuration 得来的
    }

    document.ready(function() {
        tocbot.init(obj_merge(tocbot_default_config, {
            collapseDepth: 1
        }));
    });

    function expand_toc() {
        var b = document.querySelector('.tocbot-toc-expand');
        var expanded = b.getAttribute('data-expanded');
        expanded ? b.removeAttribute('data-expanded') : b.setAttribute('data-expanded', true);
        tocbot.refresh(obj_merge(tocbot_default_config, {
            collapseDepth: expanded ? 1 : DEPTH_MAX
        }));
        b.innerText = expanded ? 'Expand all' : 'Collapse all';
    }

    function go_top() {
        window.scrollTo(0, 0);
    }

    function go_bottom() {
        window.scrollTo(0, document.body.scrollHeight);
    }

    function obj_merge(target, source) {
        for (var item in source) {
            if (source.hasOwnProperty(item)) {
                target[item] = source[item];
            }
        }
        return target;
    }
</script>
    

    
    <article class="post-wrap">
        <header class="post-header">
            <h1 class="post-title">Neutron学习</h1>
            
                <div class="post-meta">
                    
                        Author: <a itemprop="author" rel="author" href="/">Ian Tang</a>
                    

                    
                        <span class="post-time">
                        Date: <a href="#">十一月 27, 2022&nbsp;&nbsp;10:42:00</a>
                        </span>
                    
                    
                        <span class="post-category">
                    Category:
                            
                                <a href="/categories/%E5%BA%94%E7%94%A8%EF%BC%9A%E5%BA%94%E7%94%A8%E7%AC%94%E8%AE%B0/">应用：应用笔记</a>
                            
                        </span>
                    
                </div>
            
        </header>

        <div class="post-content">
            <h1 id="网络叠加模式VLAN、VxLAN、GRE"><a href="#网络叠加模式VLAN、VxLAN、GRE" class="headerlink" title="网络叠加模式VLAN、VxLAN、GRE"></a>网络叠加模式VLAN、VxLAN、GRE</h1><p><strong>问题导读</strong><br><strong>1.什么是叠加网络？</strong><br><strong>2.什么是VLAN，它的作用是什么？</strong><br><strong>3.为什么会产生VXLAN？</strong><br><strong>4.隧道技术有什么具体应用？</strong></p>
<h3 id="什么是叠加网络"><a href="#什么是叠加网络" class="headerlink" title="什么是叠加网络"></a><strong>什么是叠加网络</strong></h3><p>1.一个数据包(或帧)封装在另一个数据包内;被封装的包转发到隧道端点后再被拆装。<br>2.叠加网络就是使用这种所谓“包内之包”的技术安全地将一个网络隐藏在另一个 网络中，然后将网络区段进行迁移。</p>
<h3 id="一、VLAN介绍"><a href="#一、VLAN介绍" class="headerlink" title="一、VLAN介绍"></a><strong>一、VLAN介绍</strong></h3><p><strong>VLAN</strong>，是英文Virtual Local Area Network的缩写，中文名为”虚拟局域网”， VLAN是<br>一种将局域网（LAN）设备从逻辑上划分（注意，不是从物理上划分）成一个个网段（或者<br>说是更小的局域网LAN），从而实现虚拟工作组（单元）的数据交换技术。<br>VLAN这一新兴技术主要应用于交换机和路由器中，但目前主流应用还是在交换机之中<br>。不过不是所有交换机都具有此功能，只有三层以上交换机才具有此功能，这一点可以查<br>看相应交换机的说明书即可得知。</p>
<p><strong>VLAN的好处主要有三个：</strong><br>(1)端口的分隔。即便在同一个交换机上，处于不同VLAN的端口也是不能通信的。这<br>样一个物理的交换机可以当作多个逻辑的交换机使用。<br>(2)网络的安全。不同VLAN不能直接通信，杜绝了广播信息的不安全性。<br>(3)灵活的管理。更改用户所属的网络不必换端口和连线，只更改软件配置就可以了。</p>
<h3 id="二、VXLAN介绍"><a href="#二、VXLAN介绍" class="headerlink" title="二、VXLAN介绍"></a><strong>二、VXLAN介绍</strong></h3><p><strong>什么是VXLAN</strong><br>VXLAN全称Virtual eXtensible LAN，是一种覆盖网络技术或隧道技术。VXLAN将虚拟机发出的数据包封装在UDP中，并使用物理网络的IP&#x2F;MAC作为outer-header进行封装，然后在物理IP网上传输，到达目的地后由隧道终结点解封并将数据发送给目标虚拟机。</p>
<p><strong>为什么需要Vxlan</strong></p>
<ol>
<li><p>vlan的数量限制<br>  4096个vlan远不能满足大规模云计算数据中心的需求</p>
</li>
<li><p>物理网络基础设施的限制<br>  基于IP子网的区域划分限制了需要二层网络连通性的应用负载的部署</p>
</li>
<li><p>TOR交换机MAC表耗尽<br>  虚拟化以及东西向流量导致更多的MAC表项</p>
</li>
<li><p>多租户场景<br>  IP地址重叠？</p>
</li>
</ol>
<p><strong>什么是隧道技术</strong></p>
<p>隧道技术（Tunneling）是一种通过使用互联网络的基础设施在网络之间传递数据的方式。使用隧道传递的数据（或负载）可以是不同协议的数据帧或包。隧道协议将其它协议的数据帧或包重新封装然后通过隧道发送。新的帧头提供路由信息，以便通过互联网传递被封装的负载数据。<br>  这里所说的隧道类似于点到点的连接，这种方式能够使来自许多信息源的网络业务在同一个基础设施中通过不同的隧道进行传输。隧道技术使用点对点通信协议代替了交换连接，通过路由网络来连接数据地址。隧道技术允许授权移动用户或已授权的用户在任何时间、任何地点访问企业网络。<br>  通过隧道的建立，可实现：* 将数据流强制送到特定的地址* 隐藏私有的网络地址* 在IP网上传递非IP数据包* 提供数据安全支持</p>
<p><strong>隧道技术好处</strong><br>隧道协议有很多好处，例如在拨号网络中，用户大都接受ISP分配的动态IP地址，而企业网一般均采用防火墙、NAT等安全措施来保护自己的网络，企业员工通过ISP拨号上网时就不能穿过防火墙访问企业内部网资源。采用隧道协议后，企业拨号用户就可以得到企业内部网IP地址，通过对PPP帧进行封装，用户数据包可以穿过防火墙到达企业内部网。</p>
<p><strong>隧道的应用</strong><br>VPN具体实现是采用隧道技术，将企业网的数据封装在隧道中进行传输。隧道协议可分为第二层隧道协议PPTP、L2F、L2TP和第三层隧道协议GRE、IPsec。它们的本质区别在于用户的数据包是被封装在哪种数据包中在隧道中传输的。</p>
<h3 id="三、GRE介绍"><a href="#三、GRE介绍" class="headerlink" title="三、GRE介绍"></a><strong>三、GRE介绍</strong></h3><p><strong>GRE特点</strong><br>1.跨不同网络实现二次IP通信<br>2.L3上面包装L3<br>3.封装在IP报文中<br>4.点对点隧道</p>
<p><strong>GRE好处</strong><br>不用变更底层网络架构重建L2、L3通信<br>实现不同host之间网络guest 互通<br>方便guest 迁移<br>支持网络数量扩大</p>
<p><strong>对于GRE遂道，缺点主要是</strong></p>
<p>一是增加了GRE表头会导致本应由交换机硬件来分片的变成由软件来分片（STT技术可以弥补这一点）；<br>二是GRE广播，且遂道将虚拟二层打通了，广播风暴更厉害。但对于虚机来说，因为虚拟交换机是完全能够知道虚机的IP和MAC地址的映射关系的，根本不需要通过ARP广播来根据IP找MAC地址，目前Neutron中有这类似的blueprint可以禁止广播。所以个人比较看好STT技术，因为目前openvswitch与linux kernel还未实现STT，所以Neutron目前没有STT插件（但有VXLAN和GRE插件）。</p>
<h1 id="什么是Tap-Tun、网桥"><a href="#什么是Tap-Tun、网桥" class="headerlink" title="什么是Tap-Tun、网桥"></a>什么是Tap-Tun、网桥</h1><h3 id="什么是Tap-x2F-Tun"><a href="#什么是Tap-x2F-Tun" class="headerlink" title="什么是Tap&#x2F;Tun"></a>什么是Tap&#x2F;Tun</h3><p>在计算机网络中，TUN与TAP是操作系统内核中的虚拟网络设备。不同于普通靠硬件网路板卡实现的设备，这些虚拟的网络设备全部用软件实现，并向运行于操作系统上的软件提供与硬件的网络设备完全相同的功能。</p>
<p><strong>TAP</strong> 等同于一个<strong>以太网设备</strong>，它操作第二层数据包如以太网数据帧。<strong>TUN</strong>模拟了<strong>网络层设备</strong>，操作第三层数据包比如IP数据封包。</p>
<p>操作系统通过TUN&#x2F;TAP设备向绑定该设备的用户空间的程序发送数据，反之，用户空间的程序也可以像操作硬件网络设备那样，通过TUN&#x2F;TAP设备发送数据。在后种情况下，TUN&#x2F;TAP设备向操作系统的网络栈投递（或“注入”）数据包，从而模拟从外部接受数据的过程。</p>
<p>服务器如果拥有TUN&#x2F;TAP模块，就可以开启VPN代理功能。</p>
<h3 id="什么是网桥"><a href="#什么是网桥" class="headerlink" title="什么是网桥"></a>什么是网桥</h3><p>网桥工作在数据链路层，将两个局域网（LAN）连起来，根据MAC地址（物理地址）来转发帧，可以看作一个“低层的路由器”（路由器工作在网络层，根据网络地址如IP地址进行转发）。它可以有效地联接两个LAN，使本地通信限制在本网段内，并转发相应的信号至另一网段，网桥通常用于联接数量不多的、同一类型的网段。<br>网络虚拟化中最重要的两个东西：Linux Bridge 和 VLAN</p>
<h2 id="Linux-Bridge-基本概念"><a href="#Linux-Bridge-基本概念" class="headerlink" title="Linux Bridge 基本概念"></a>Linux Bridge 基本概念</h2><p>假设宿主机有 1 块与外网连接的物理网卡 eth0，上面跑了 1 个虚机 VM1，现在有个问题是：<br>如何让 VM1 能够访问外网？</p>
<p>至少有两种方案</p>
<ol>
<li>将物理网卡eth0直接分配给VM1，但随之带来的问题很多：<br>宿主机就没有网卡，无法访问了；<br>新的虚机，比如 VM2 也没有网卡。<br>下面看推荐的方案</li>
<li>给 VM1 分配一个虚拟网卡 vnet0，通过 Linux Bridge br0 将 eth0 和 vnet0 连接起来，如下图所示</li>
</ol>
<p><img src="https://pic.downk.cc/item/5eb69d4bc2a9a83be502b076.png"></p>
<p>Linux Bridge 是 Linux 上用来做 TCP&#x2F;IP 二层协议交换的设备，其功能大家可以简单的理解为是一个二层交换机或者 Hub。多个网络设备可以连接到同一个 Linux Bridge，当某个设备收到数据包时，Linux Bridge 会将数据转发给其他设备。</p>
<p>在上面这个例子中，当有数据到达 eth0 时，br0 会将数据转发给 vnet0，这样 VM1 就能接收到来自外网的数据；<br>反过来，VM1 发送数据给 vnet0，br0 也会将数据转发到 eth0，从而实现了 VM1 与外网的通信。</p>
<p>现在我们增加一个虚机 VM2，如下图所示</p>
<p><img src="https://pic.downk.cc/item/5eb69d97c2a9a83be503271f.png"></p>
<p>VM2 的虚拟网卡 vnet1 也连接到了 br0 上。<br>现在 VM1 和 VM2 之间可以通信，同时 VM1 和 VM2 也都可以与外网通信。</p>
<hr>
<p>有两点需要注意：</p>
<ol>
<li>之前宿主机的 IP 是通过 dhcp 配置在 eth0 上的；创建 Linux Bridge 之后，IP 就必须放到 br0 上了</li>
<li>在 br0 的配置信息中请注意最后一行 “bridge_ports eth0”，其作用就是将 eth0 挂到 br0 上</li>
</ol>
<p>重启宿主机，查看 IP 配置，可以看到 IP 已经放到 br0 上了</p>
<figure class="highlight plaintext"><figcaption><span>ifconfig  br0       Link encap:Ethernet  HWaddr 00:0c:29:8d:ec:be</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">          inet addr:192.168.111.107  Bcast:192.168.111.255  Mask:255.255.255.0</span><br><span class="line">          inet6 addr: fe80::20c:29ff:fe8d:ecbe/64 Scope:Link</span><br><span class="line">          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1</span><br><span class="line">          RX packets:22573 errors:0 dropped:0 overruns:0 frame:0</span><br><span class="line">          TX packets:2757 errors:0 dropped:0 overruns:0 carrier:0</span><br><span class="line">          collisions:0 txqueuelen:0 </span><br><span class="line">          RX bytes:4927580 (4.9 MB)  TX bytes:368895 (368.8 KB)</span><br><span class="line"></span><br><span class="line">eth0      Link encap:Ethernet  HWaddr 00:0c:29:8d:ec:be</span><br><span class="line">          inet6 addr: fe80::20c:29ff:fe8d:ecbe/64 Scope:Link</span><br><span class="line">          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1</span><br><span class="line">          RX packets:24388 errors:0 dropped:0 overruns:0 frame:0</span><br><span class="line">          TX packets:2816 errors:0 dropped:0 overruns:0 carrier:0</span><br><span class="line">          collisions:0 txqueuelen:1000 </span><br><span class="line">          RX bytes:5590438 (5.5 MB)  TX bytes:411558 (411.5 KB)</span><br><span class="line"></span><br><span class="line">lo        Link encap:Local Loopback</span><br><span class="line">          inet addr:127.0.0.1  Mask:255.0.0.0</span><br><span class="line">          inet6 addr: ::1/128 Scope:Host</span><br><span class="line">          UP LOOPBACK RUNNING  MTU:65536  Metric:1</span><br><span class="line">          RX packets:146 errors:0 dropped:0 overruns:0 frame:0</span><br><span class="line">          TX packets:146 errors:0 dropped:0 overruns:0 carrier:0</span><br><span class="line">          collisions:0 txqueuelen:0 </span><br><span class="line">          RX bytes:10521 (10.5 KB)  TX bytes:10521 (10.5 KB)</span><br><span class="line"></span><br><span class="line">virbr0    Link encap:Ethernet  HWaddr 72:db:fb:f2:19:91</span><br><span class="line">          inet addr:192.168.122.1  Bcast:192.168.122.255  Mask:255.255.255.0</span><br><span class="line">          UP BROADCAST MULTICAST  MTU:1500  Metric:1</span><br><span class="line">          RX packets:0 errors:0 dropped:0 overruns:0 frame:0</span><br><span class="line">          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0</span><br><span class="line">          collisions:0 txqueuelen:0 </span><br><span class="line">          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)</span><br></pre></td></tr></table></figure>

<p>用 brctl show 查看当前 Linux Bridge 的配置。<br>eth0 已经挂到 br0 上了</p>
<figure class="highlight plaintext"><figcaption><span>brctl show</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">bridge name     bridge id          STP enabled    interfaces</span><br><span class="line">br0        8000.000c298decbe       no                    eth0</span><br><span class="line">virbr0     8000.000000000000       yes</span><br></pre></td></tr></table></figure>

<p>除了 br0，大家应该注意到还有一个 virbr0 的 Bridge，而且 virbr0 上已经配置了 IP 地址 192.168.122.1。<br>virbr0 的作用在后面介绍。</p>
<p>启动 VM1，看会发生什么</p>
<figure class="highlight plaintext"><figcaption><span>virsh start VM1</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Domain VM1 started</span><br><span class="line"></span><br><span class="line"># brctl show</span><br><span class="line">bridge name     bridge id               STP enabled   interfaces</span><br><span class="line">br0             8000.000c298decbe       no                  eth0</span><br><span class="line">                                                           vnet0</span><br><span class="line">virbr0          8000.000000000000       yes</span><br></pre></td></tr></table></figure>

<p>brctl show 告诉我们 br0 下面添加了一个 vnet0 设备，通过 virsh 确认这就是VM1的虚拟网卡。</p>
<figure class="highlight plaintext"><figcaption><span>virsh domiflist</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">VM1 Interface  Type       Source     Model       MAC </span><br><span class="line">------------------------------------------------------- </span><br><span class="line">vnet0      bridge     br0        rtl8139     52:54:00:75:dd:1a</span><br></pre></td></tr></table></figure>

<p>VM1 的 IP 是 DHCP 获得的（设置静态 IP 当然也可以），通过 virt-manager 控制台登录 VM1，查看 IP。</p>
<figure class="highlight plaintext"><figcaption><span>ifconfig eth0      Link encap:Ethernet  HWaddr 52:54:00:75:dd:1a</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">inet addr:192.168.111.106  Bcast:192.168.111.255  Mask:255.255.255.0</span><br><span class="line">inet6 addr: fe80::5054:ff:fe75:dd1a/64 Scope:Link</span><br><span class="line">UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1</span><br><span class="line">RX packets:400 errors:0 dropped:0 overruns:0 frame:0</span><br><span class="line">TX packets:101 errors:0 dropped:0 overruns:0 carrier:0</span><br><span class="line">collisions:0 txqueuelen:1000 </span><br><span class="line">RX bytes:41950 (41.9 KB)  TX bytes:12583 (12.5 KB)</span><br></pre></td></tr></table></figure>

<p>VM1 通过 DHCP 拿到的 IP 是 192.168.111.106，与宿主机（IP为192.168.111.107）是同一个网段。Ping 一下外网</p>
<figure class="highlight plaintext"><figcaption><span>ping www.baidu.com</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">PING www.a.shifen.com (180.97.33.108) 56(84) bytes of data. </span><br><span class="line">64 bytes from 180.97.33.108: icmp_seq=1 ttl=53 time=34.9 ms</span><br><span class="line">64 bytes from 180.97.33.108: icmp_seq=2 ttl=53 time=36.2 ms</span><br><span class="line">64 bytes from 180.97.33.108: icmp_seq=3 ttl=53 time=38.8 ms</span><br></pre></td></tr></table></figure>

<hr>
<h2 id="virbr0"><a href="#virbr0" class="headerlink" title="virbr0"></a>virbr0</h2><p>virbr0 是 KVM 默认创建的一个 Bridge，其作用是为连接其上的虚机网卡提供 NAT 访问外网的功能。</p>
<p><font size=2 color=red><strong>NAT</strong>是网络地址穿透技术，内部网段的ip地址共用一个公共ip地址，内部发送报文的头部都由NAT网关自动替换为公共ip，接受报文同理</font></p>
<p>也就是说一个物理主机上建立的多个虚机相当于一个局域网，不可能为每个虚拟网卡都分配公共ip，则通过virbr0充当NAT网关的作用，对外共用一个ip地址。</p>
<p>virbr0 默认分配了一个IP 192.168.122.1，并为连接其上的其他虚拟网卡提供 DHCP 服务。</p>
<p>在 virt-manager 打开 VM1 的配置界面，网卡 Source device 选择 “default”，将 VM1 的网卡挂在 virbr0 上。</p>
<p>启动 VM1，brctl show 可以查看到 vnet0 已经挂在了 virbr0 上。</p>
<figure class="highlight plaintext"><figcaption><span>brctl show</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">bridge name bridge id STP enabled interfaces</span><br><span class="line">br0 8000.000c298decbe no eth0</span><br><span class="line">virbr0 8000.fe540075dd1a yes vnet0</span><br></pre></td></tr></table></figure>

<p>用 virsh 命令确认 vnet 就是 VM1 的虚拟网卡。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"># virsh domiflist VM1</span><br><span class="line"></span><br><span class="line">Interface Type Source Model MAC</span><br><span class="line">——————————————————-</span><br><span class="line">vnet0 network default rtl8139 52:54:00:75:dd:1a</span><br></pre></td></tr></table></figure>

<p>virbr0 使用 dnsmasq 提供 DHCP 服务，可以在宿主机中查看该进程信息</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"># ps -elf|grep dnsmasq</span><br><span class="line"></span><br><span class="line">5 S libvirt+ 2422 1 0 80 0 - 7054 poll_s 11:26 ? 00:00:00 /usr/sbin/dnsmasq –conf-file=/var/lib/libvirt/dnsmasq/default.conf</span><br></pre></td></tr></table></figure>

<p>在 &#x2F;var&#x2F;lib&#x2F;libvirt&#x2F;dnsmasq&#x2F; 目录下有一个 default.leases 文件，当 VM1 成功获得 DHCP 的 IP 后，可以在该文件中查看到相应的信息</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"># cat /var/lib/libvirt/dnsmasq/default.leases</span><br><span class="line"></span><br><span class="line">1441525677 52:54:00:75:dd:1a 192.168.122.6 ubuntu *</span><br></pre></td></tr></table></figure>

<p>上面显示 192.168.122.6 已经分配给 MAC 地址为 52:54:00:75:dd:1a 的网卡，这正是 vnet0 的 MAC。之后就可以使用该 IP 访问 VM1 了。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"># ssh 192.168.122.6</span><br><span class="line"></span><br><span class="line">root@192.168.122.6’s password:</span><br><span class="line">Welcome to Ubuntu 14.04.2 LTS (GNU/Linux 3.16.0-30-generic x86_64)</span><br><span class="line">Last login: Sun Sep 6 01:30:23 2015</span><br><span class="line">root@VM1:~# ifconfig</span><br><span class="line">eth0 Link encap:Ethernet HWaddr 52:54:00:75:dd:1a</span><br><span class="line">inet addr:192.168.122.6 Bcast:192.168.122.255 Mask:255.255.255.0</span><br><span class="line">inet6 addr: fe80::5054:ff:fe75:dd1a/64 Scope:Link</span><br><span class="line">UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1</span><br><span class="line">RX packets:61 errors:0 dropped:0 overruns:0 frame:0</span><br><span class="line">TX packets:66 errors:0 dropped:0 overruns:0 carrier:0</span><br><span class="line">collisions:0 txqueuelen:1000</span><br><span class="line">RX bytes:7453 (7.4 KB) TX bytes:8649 (8.6 KB)</span><br><span class="line"></span><br><span class="line">Ping一下外网。</span><br><span class="line"></span><br><span class="line">root@VM1:~# ping www.baidu.com</span><br><span class="line">PING www.a.shifen.com (180.97.33.107) 56(84) bytes of data.</span><br><span class="line">64 bytes from 180.97.33.107: icmp_seq=1 ttl=52 time=36.9 ms</span><br><span class="line">64 bytes from 180.97.33.107: icmp_seq=2 ttl=52 time=119 ms</span><br><span class="line">64 bytes from 180.97.33.107: icmp_seq=3 ttl=52 time=88.5 ms</span><br><span class="line">64 bytes from 180.97.33.107: icmp_seq=4 ttl=52 time=38.0 ms</span><br><span class="line">64 bytes from 180.97.33.107: icmp_seq=5 ttl=52 time=122 ms</span><br></pre></td></tr></table></figure>

<p>没有问题，可以访问外网，说明 NAT 起作用了。</p>
<p>需要说明的是，使用 NAT 的虚机 VM1 可以访问外网，但外网无法直接访问 VM1。<br>因为 VM1 发出的网络包源地址并不是 192.168.122.6，而是被 NAT 替换为宿主机的 IP 地址了。</p>
<p>这个与使用 br0 不一样，在 br0 的情况下，VM1 通过自己的 IP 直接与外网通信，不会经过 NAT 地址转换。</p>
<hr>
<h2 id="VLAN"><a href="#VLAN" class="headerlink" title="VLAN"></a>VLAN</h2><p>LAN 表示 Local Area Network，本地局域网，通常使用 Hub 和 Switch 来连接 LAN 中的计算机。一般来说，两台计算机连入同一个 Hub 或者 Switch 时，它们就在同一个 LAN 中。</p>
<p>一个 LAN 表示一个广播域。<br>其含义是：LAN 中的所有成员都会收到任意一个成员发出的广播包。</p>
<p>VLAN 表示 Virtual LAN。<br>一个带有 VLAN 功能的switch 能够将自己的端口划分出多个 LAN。<br>计算机发出的广播包可以被同一个 LAN 中其他计算机收到，但位于其他 LAN 的计算机则无法收到。<br>简单地说，VLAN 将一个交换机分成了多个交换机，限制了广播的范围，在二层将计算机隔离到不同的 VLAN 中。</p>
<p>比方说，有两组机器，Group A 和 B。<br>我们想配置成 Group A 中的机器可以相互访问，Group B 中的机器也可以相互访问，但是 A 和 B 中的机器无法互相访问。<br>一种方法是使用两个交换机，A 和 B 分别接到一个交换机。<br>另一种方法是使用一个带 VLAN 功能的交换机，将 A 和 B 的机器分别放到不同的 VLAN 中。</p>
<p>请注意：<br>VLAN 的隔离是二层上的隔离，A 和 B 无法相互访问指的是二层广播包（比如 arp）无法跨越 VLAN 的边界。<br>但在三层（比如IP）上是可以通过路由器让 A 和 B 互通的。概念上一定要分清。</p>
<p>现在的交换机几乎都是支持 VLAN 的。<br>通常交换机的端口有两种配置模式： Access 和 Trunk。看下图<br><img src="https://pic.downk.cc/item/5eb6a970c2a9a83be5145717.png"></p>
<p>Access 口<br>这些端口被打上了 VLAN 的标签，表明该端口属于哪个 VLAN。<br>不同 VLAN 用 VLAN ID 来区分，VLAN ID 的 范围是 1-4096。<br>Access 口都是直接与计算机网卡相连的，这样从该网卡出来的数据包流入 Access 口后就被打上了所在 VLAN 的标签。<br>Access 口只能属于一个 VLAN。</p>
<p>Trunk 口<br>假设有两个交换机 A 和 B。<br>A 上有 VLAN1（红）、VLAN2（黄）、VLAN3（蓝）；B 上也有 VLAN1、2、3<br>那如何让 AB 上相同 VLAN 之间能够通信呢？</p>
<p>办法是将 A 和 B 连起来，而且连接 A 和 B 的端口要允许 VLAN1、2、3 三个 VLAN 的数据都能够通过。这样的端口就是Trunk口了。<br>VLAN1、2、3 的数据包在通过 Trunk 口到达对方交换机的过程中始终带着自己的 VLAN 标签。</p>
<p>了解了 VLAN 的概念之后，我们来看 KVM 虚拟化环境下是如何实现 VLAN 的。还是先看图，</p>
<p><img src="https://pic.downk.cc/item/5eb6a9cac2a9a83be514ecf7.png"></p>
<p>eth0 是宿主机上的物理网卡，有一个命名为 eth0.10 的子设备与之相连。<br>eth0.10 就是 VLAN 设备了，其 VLAN ID 就是 VLAN 10。<br>eth0.10 挂在命名为 brvlan10 的 Linux Bridge 上，虚机 VM1 的虚拟网卡 vent0 也挂在 brvlan10 上。</p>
<p>这样的配置其效果就是：<br>宿主机用软件实现了一个交换机（当然是虚拟的），上面定义了一个 VLAN10。<br>eth0.10，brvlan10 和 vnet0 都分别接到 VLAN10 的 Access口上。<br>而 eth0 就是一个 Trunk 口。<br>VM1 通过 vnet0 发出来的数据包会被打上 VLAN10 的标签。</p>
<p>eth0.10 的作用是：定义了 VLAN10<br>brvlan10 的作用是：Bridge 上的其他网络设备自动加入到 VLAN10 中</p>
<p>我们再增加一个 VLAN20，见下图</p>
<p>这样虚拟交换机就有两个 VLAN 了，VM1 和 VM2 分别属于 VLAN10 和 VLAN20。<br>对于新创建的虚机，只需要将其虚拟网卡放入相应的 Bridge，就能控制其所属的 VLAN。</p>
<p>VLAN 设备总是以母子关系出现，母子设备之间是一对多的关系。<br>一个母设备（eth0）可以有多个子设备（eth0.10，eth0.20 ……），而一个子设备只有一个母设备。</p>
<h1 id="什么是交换机、路由器、DHCP"><a href="#什么是交换机、路由器、DHCP" class="headerlink" title="什么是交换机、路由器、DHCP"></a>什么是交换机、路由器、DHCP</h1><p>在使用neutron过程中，会用到创建虚拟网桥、虚拟交换机、虚拟路由器等，这些东西到底是什么？DHCP到底又什么用？</p>
<h3 id="交换机："><a href="#交换机：" class="headerlink" title="交换机："></a>交换机：</h3><p>工作在数据链路层，交换机拥有一条很高带宽的背部总线和内部交换矩阵。交换机的所有的端口都挂接在这条背部总线上，控制电路收到数据包以后，处理端口会查找内存中的地址对照表以确定目的MAC（网卡的硬件地址）的NIC（网卡）挂接在哪个端口上，通过内部交换矩阵迅速将数据包传送到目的端口，目的MAC若不存在，广播到所有的端口，接收端口回应后交换机会“学习”新的MAC地址，并把它添加入内部MAC地址表中。</p>
<h3 id="路由器："><a href="#路由器：" class="headerlink" title="路由器："></a>路由器：</h3><p>为不同网络之间互相连接的枢纽，路由器系统构成了基于TCP&#x2F;IP 的国际互联网络Internet 的主体脉络，也可以说，路由器构成了Internet的骨架。它的处理速度是网络通信的主要瓶颈之一，它的可靠性则直接影响着网络互连的质量。因此，在园区网、地区网、乃至整个Internet研究领域中，路由器技术始终处于核心地位，其发展历程和方向，成为整个Internet研究的一个缩影。</p>
<h3 id="DHCP："><a href="#DHCP：" class="headerlink" title="DHCP："></a>DHCP：</h3><p>在一个使用TCP&#x2F;IP协议的网络中，每一台计算机都必须至少有一个IP地址，才能与其他计算机连接通信。为了便于统一规划和管理网络中的IP地址，DHCP（Dynamic Host Configure Protocol，动态主机配置协议）应运而生了。这种网络服务有利于对校园网络中的客户机IP地址进行有效管理，而不需要一个一个手动指定IP地址。</p>
<h1 id="什么是Open-vSwitch"><a href="#什么是Open-vSwitch" class="headerlink" title="什么是Open-vSwitch"></a>什么是Open-vSwitch</h1><h3 id="如何理解网桥"><a href="#如何理解网桥" class="headerlink" title="如何理解网桥"></a>如何理解网桥</h3><p>Bridge（桥）是Linux上用来做TCP&#x2F;IP二层协议交换的设备，与现实世界中的交换机功能相似。Bridge设备实例可以和Linux上其他网络设备实例连接，既attach一个从设备，类似于在现实世界中的交换机和一个用户终端之间连接一根网线。当有数据到达时，Bridge会根据报文中的MAC信息进行广播、转发、丢弃处理。</p>
<h3 id="Open-vSwitch"><a href="#Open-vSwitch" class="headerlink" title="Open vSwitch"></a>Open vSwitch</h3><p>Open vSwitch的目标，是做一个具有产品级质量的多层虚拟交换机。通过可编程扩展，可以实现大规模网络的自动化（配置、管理、维护）。它支持现有标准管理接口和协议（比如netFlow，sFlow，SPAN，RSPAN，CLI，LACP，802.1ag等，熟悉物理网络维护的管理员可以毫不费力地通过Open vSwitch转向虚拟网络管理）。总的来说，它被设计为支持分布在多个物理服务器，例如VMware的vNetwork分布式vSwitch或思科的Nexus1000V。</p>
<p>那么什么是虚拟交换？虚拟交换就是利用虚拟平台，通过软件的方式形成交换机部件。跟传统的物理交换机相比，虚拟交换机同样具备众多优点，一是配置更加灵活。一台普通的服务器可以配置出数十台甚至上百台虚拟交换机，且端口数目可以灵活选择。例如，VMware的ESX一台服务器可以仿真出248台虚拟交换机，且每台交换机预设虚拟端口即可达56个；二是成本更加低廉，通过虚拟交换往往可以获得昂贵的普通交换机才能达到的性能，例如微软的Hyper-V平台，虚拟机与虚拟交换机之间的联机速度轻易可达10Gbps</p>
<p>通俗来讲，Open vSwitch是一个由Nicira Networks主导的开源项目，通过运行在虚拟化平台上的虚拟交换机，为本台物理机上的VM提供二层网络接入， 跟云中的其它物理交换机一样工作在Layer 2层。Open vSwitch充分考虑了在不同虚拟化平台间的移植性，采用平台无关的C语言开发。</p>
<h3 id="Open-vSwitch的作用"><a href="#Open-vSwitch的作用" class="headerlink" title="Open vSwitch的作用"></a>Open vSwitch的作用</h3><p>你可能会问，我为什么有必要在自己的云架构中使用它呢？它能给我的云带来什么？</p>
<p>OK。需求决定一切，如果你只是自己搞一台Host，在上面虚拟几台VM做实验。或者小型创业公司，通过在五台十台机器上的虚拟化，创建一些VM给公司内部开发测试团队使用。那么对你而言，网络虚拟化的迫切性并不强烈。也许你更多考虑的，是VM的可靠接入：和物理机一样有效获取网络连接，能够RDP访问。Linux Kernel自带的桥接模块就可以很好的解决这一问题。原理上讲，正确配置桥接，并把VM的virtual nic连接在桥接器上就OK啦。很多虚拟化平台的早期解决方案也是如此，自动配置并以向用户透明的方式提供虚拟机接入。如果你是OpenStack的fans，那Nova就更好地帮你完成了一系列网络接入设置。Open vSwitch在WHY-OVS这篇文章中，第一句话就高度赞扬了Linux bridge：</p>
<p>“We love the existing network stack in Linux. It is robust, flexible, and feature rich. Linux already contains an in-kernel L2 switch (the Linux bridge) which can be used by VMs for inter-VM communication. So, it is reasonable to ask why there is a need for a new network switch.”</p>
<p>但是，如果你是大型数据中心的网络管理员，一朵没有网络虚拟化支持的云，将是无尽的噩梦。</p>
<p>在传统数据中心中，网络管理员习惯了每台物理机的网络接入均可见并且可配置。通过在交换机某端口的策略配置，可以很好控制指定物理机的网络接入，访问策略，网络隔离，流量监控，数据包分析，Qos配置，流量优化等。</p>
<p>有了云，网络管理员仍然期望能以per OS&#x2F;per port的方式管理。如果没有网络虚拟化技术的支持，管理员只能看到被桥接的物理网卡，其上川流不息地跑着n台VM的数据包。仅凭物理交换机支持，管理员无法区分这些包属于哪个OS哪个用户，只能望云兴叹乎？简单列举常见的几种需求，Open vSwitch现有版本很好地解决了这些需求。</p>
<p><strong>需求一</strong>：网络隔离。物理网络管理员早已习惯了把不同的用户组放在不同的VLAN中，例如研发部门、销售部门、财务部门，做到二层网络隔离。Open vSwitch通过在host上虚拟出一个软件交换机，等于在物理交换机上级联了一台新的交换机，所有VM通过级联交换机接入，让管理员能够像配置物理交换机一样把同一台host上的众多VM分配到不同VLAN中去；</p>
<p>  <strong>需求二</strong>：QoS配置。在共享同一个物理网卡的众多VM中，我们期望给每台VM配置不同的速度和带宽，以保证核心业务VM的网络性能。通过在Open vSwitch端口上，给各个VM配置QoS，可以实现物理交换机的traffic queuing和traffic shaping功能。</p>
<p>  <strong>需求三</strong>：流量监控，Netflow，sFlow。物理交换机通过xxFlow技术对数据包采样，记录关键域，发往Analyzer处理。进而实现包括网络监控、应用软件监控、用户监控、网络规划、安全分析、会计和结算、以及网络流量数据库分析和挖掘在内的各项操作。例如，NetFlow流量统计可以采集的数据非常丰富，包括：数据流时戳、源IP地址和目的IP地址、 源端口号和目的端口号、输入接口号和输出接口号、下一跳IP地址、信息流中的总字节数、信息流中的数据包数量、信息流中的第一个和最后一个数据包时戳、源AS和目的AS，及前置掩码序号等。xxFlow因其方便、快捷、动态、高效的特点，为越来越多的网管人员所接受，成为互联网安全管理的重要手段，特别是在较大网络的管理中，更能体现出其独特优势。没错，有了Open vSwitch，作为网管的你，可以把xxFlow的强大淋漓尽致地应用在VM上！</p>
<p> <strong>需求四</strong>：数据包分析，Packet Mirror。物理交换机的一大卖点，当对某一端口的数据包感兴趣时（for trouble shooting , etc），可以配置各种span（SPAN, RSPAN, ERSPAN），把该端口的数据包复制转发到指定端口，通过抓包工具进行分析。Open vSwitch官网列出了对SPAN, RSPAN, and GRE-tunneled mirrors的支持。</p>
<p>只是在Open vSwitch上实现物理交换机的现有功能？那绝对不是Nicira的风格。</p>
<p>云中的网络，绝不仅仅需要传统物理交换机已有的功能。云对网络的需求，推动了Software Defined Network越来越火。而在各种SDN解决方案中，OpenFlow无疑是最引人瞩目的。Flow Table + Controller的架构，为新服务新协议提供了绝佳的开放性平台。Nicira把对Openflow的支持引入了Open vSwitch。引入以下模块：</p>
<p>·      ovs-openflowd — OpenFlow交换机；</p>
<p>·      ovs-controller — OpenFlow控制器；</p>
<p>·      ovs-ofctl — Open Flow 的命令行配置接口；</p>
<p>·      ovs-pki — 创建和管理公钥框架；</p>
<p>·      tcpdump的补丁 — 解析OpenFlow的消息；</p>
<h3 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h3><p>关于ovs一个很入门的参考资料：</p>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/elihe2011/article/details/122346128">https://blog.csdn.net/elihe2011/article/details/122346128</a></p>
<h1 id="dnsmasq"><a href="#dnsmasq" class="headerlink" title="dnsmasq"></a>dnsmasq</h1><p>openstack概念中，我们会看到Dnsmasq，那么它的作用是什么？简单来讲，是为了提高dns性能的。<br>混杂模式又分为集线器模式，及交换机模式，这里不在细分，只是对这个模式有一个简单的感性认知即可.</p>
<h3 id="dnsmasq-1"><a href="#dnsmasq-1" class="headerlink" title="dnsmasq"></a>dnsmasq</h3><p>提供 DNS 缓存和 DHCP 服务功能。作为域名解析服务器(DNS)，dnsmasq可以通过缓存 DNS 请求来提高对访问过的网址的连接速度。作为DHCP 服务器，dnsmasq 可以为局域网电脑提供内网ip地址和路由。DNS和DHCP两个功能可以同时或分别单独实现。dnsmasq轻量且易配置，适用于个人用户或少于50台主机的网络。</p>
<h3 id="混杂模式（Promiscuous-Mode）"><a href="#混杂模式（Promiscuous-Mode）" class="headerlink" title="混杂模式（Promiscuous Mode）"></a>混杂模式（Promiscuous Mode）</h3><p>是指一台机器能够接收所有经过它的数据流，而不论其目的地址是否是他。是相对于通常模式（又称“非混杂模式”）而言的。这被网络管理员使用来诊断网络问题，但是也被无认证的想偷听网络通信（其可能包括密码和其它敏感的信息）的人利用。</p>
<h1 id="iptables"><a href="#iptables" class="headerlink" title="iptables"></a>iptables</h1><p>iptables是防火墙功能，是处于网络边界的控制网络访问的功能，分为硬件防火墙和软件防火墙。</p>
<p>目前市面上比较常见的有3、4层的防火墙，叫网络层的防火墙，还有7层的防火墙，其实是代理层的网关。</p>
<p>对于TCP&#x2F;IP的七层模型来讲，我们知道第三层是网络层，三层的防火墙会在这层对源地址和目标地址进行检测。但是对于七层的防火墙，不管你源端口或者目标端口，源地址或者目标地址是什么，都将对你所有的东西进行检查。所以，对于设计原理来讲，七层防火墙更加安全，但是这却带来了效率更低。所以市面上通常的防火墙方案，都是两者结合的。而又由于我们都需要从防火墙所控制的这个口来访问，所以防火墙的工作效率就成了用户能够访问数据多少的一个最重要的控制，配置的不好甚至有可能成为流量的瓶颈。</p>
<p>​ 防火墙，其实说白了讲，就是用于实现Linux下访问控制的功能的，它分为硬件的或者软件的防火墙两种。无论是在哪个网络中，防火墙工作的地方一定是在网络的边缘。而我们的任务就是需要去定义到底防火墙如何工作，这就是防火墙的策略，规则，以达到让它对出入网络的IP、数据进行检测。</p>
<p>​ 目前市面上比较常见的有3、4层的防火墙，叫网络层的防火墙，还有7层的防火墙，其实是代理层的网关。</p>
<p>​ 对于TCP&#x2F;IP的七层模型来讲，我们知道第三层是网络层，三层的防火墙会在这层对源地址和目标地址进行检测。但是对于七层的防火墙，不管你源端口或者目标端口，源地址或者目标地址是什么，都将对你所有的东西进行检查。所以，对于设计原理来讲，七层防火墙更加安全，但是这却带来了效率更低。所以市面上通常的防火墙方案，都是两者结合的。而又由于我们都需要从防火墙所控制的这个口来访问，所以防火墙的工作效率就成了用户能够访问数据多少的一个最重要的控制，配置的不好甚至有可能成为流量的瓶颈。</p>
<h3 id="iptables的发展"><a href="#iptables的发展" class="headerlink" title="iptables的发展:"></a>iptables的发展:</h3><p>​ iptables的前身叫ipfirewall （内核1.x时代）,这是一个作者从freeBSD上移植过来的，能够工作在内核当中的，对数据包进行检测的一款简易访问控制工具。但是ipfirewall工作功能极其有限(它需要将所有的规则都放进内核当中，这样规则才能够运行起来，而放进内核，这个做法一般是极其困难的)。当内核发展到2.x系列的时候，软件更名为ipchains，它可以定义多条规则，将他们串起来，共同发挥作用，而现在，它叫做iptables，可以将规则组成一个列表，实现绝对详细的访问控制功能。</p>
<p>​ 他们都是工作在用户空间中，定义规则的工具，本身并不算是防火墙。它们定义的规则，可以让在内核空间当中的netfilter来读取，并且实现让防火墙工作。而放入内核的地方必须要是特定的位置，必须是tcp&#x2F;ip的协议栈经过的地方。而这个tcp&#x2F;ip协议栈必须经过的地方，可以实现读取规则的地方就叫做 netfilter.(网络过滤器)</p>
<p>作者一共在内核空间中选择了5个位置，<br>1.内核空间中：从一个网络接口进来，到另一个网络接口去的<br>2.数据包从内核流入用户空间的<br>3.数据包从用户空间流出的<br>4.进入&#x2F;离开本机的外网接口<br>5.进入&#x2F;离开本机的内网接口</p>
<h3 id="iptables的工作机制"><a href="#iptables的工作机制" class="headerlink" title="iptables的工作机制"></a>iptables的工作机制</h3><p>​ 从上面的发展我们知道了作者选择了5个位置，来作为控制的地方，但是你有没有发现，其实前三个位置已经基本上能将路径彻底封锁了，但是为什么已经在进出的口设置了关卡之后还要在内部卡呢？ 由于数据包尚未进行路由决策，还不知道数据要走向哪里，所以在进出口是没办法实现数据过滤的。所以要在内核空间里设置转发的关卡，进入用户空间的关卡，从用户空间出去的关卡。那么，既然他们没什么用，那我们为什么还要放置他们呢？因为我们在做NAT和DNAT的时候，目标地址转换必须在路由之前转换。所以我们必须在外网而后内网的接口处进行设置关卡。</p>
<p>​ 这五个位置也被称为五个钩子函数（hook functions）,也叫五个规则链。<br>​ 1.PREROUTING (路由前)<br>​ 2.INPUT (数据包流入口)<br>​ 3.FORWARD (转发管卡)<br>​ 4.OUTPUT(数据包出口)<br>​ 5.POSTROUTING（路由后）<br>​ 这是NetFilter规定的五个规则链，任何一个数据包，只要经过本机，必将经过这五个链中的其中一个链。</p>
<h3 id="防火墙的策略"><a href="#防火墙的策略" class="headerlink" title="防火墙的策略"></a>防火墙的策略</h3><p>​ 防火墙策略一般分为两种，一种叫“通”策略，一种叫“堵”策略，通策略，默认门是关着的，必须要定义谁能进。堵策略则是，大门是洞开的，但是你必须有身份认证，否则不能进。所以我们要定义，让进来的进来，让出去的出去，所以通，是要全通，而堵，则是要选择。当我们定义的策略的时候，要分别定义多条功能，其中：定义数据包中允许或者不允许的策略，filter过滤的功能，而定义地址转换的功能的则是nat选项。为了让这些功能交替工作，我们制定出了“表”这个定义，来定义、区分各种不同的工作功能和处理方式。</p>
<p>​ 我们现在用的比较多个功能有3个：<br>​ 1.filter 定义允许或者不允许的<br>​ 2.nat 定义地址转换的<br>​ 3.mangle功能:修改报文原数据</p>
<p>​ 我们修改报文原数据就是来修改TTL的。能够实现将数据包的元数据拆开，在里面做标记&#x2F;修改内容的。而防火墙标记，其实就是靠mangle来实现的。</p>
<p>小扩展:<br>对于filter来讲一般只能做在3个链上：INPUT ，FORWARD ，OUTPUT<br>对于nat来讲一般也只能做在3个链上：PREROUTING ，OUTPUT ，POSTROUTING<br>而mangle则是5个链都可以做：PREROUTING，INPUT，FORWARD，OUTPUT，POSTROUTING</p>
<p>​ iptables&#x2F;netfilter（这款软件）是工作在用户空间的，它可以让规则进行生效的，本身不是一种服务，而且规则是立即生效的。而我们iptables现在被做成了一个服务，可以进行启动，停止的。启动，则将规则直接生效，停止，则将规则撤销。<br>​ iptables还支持自己定义链。但是自己定义的链，必须是跟某种特定的链关联起来的。在一个关卡设定，指定当有数据的时候专门去找某个特定的链来处理，当那个链处理完之后，再返回。接着在特定的链中继续检查。</p>
<p>注意：规则的次序非常关键，谁的规则越严格，应该放的越靠前，而检查规则的时候，是按照从上往下的方式进行检查的。</p>
<p><a target="_blank" rel="noopener" href="https://www.aboutyun.com/forum.php?mod=viewthread&tid=9649&highlight=%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%D4%B1%EF%BF%BD%D8%B6%EF%BF%BDopenstack%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD">参考资料</a></p>
<h1 id="l2层、l3层结构"><a href="#l2层、l3层结构" class="headerlink" title="l2层、l3层结构"></a>l2层、l3层结构</h1><h3 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h3><h4 id="分层"><a href="#分层" class="headerlink" title="分层"></a>分层</h4><p>网络有上层必有上层，比如TCP的三次握手，每次握手必有ip头和mac头部；<strong>可以有下层没上层，不能有上层没下层。</strong>网络上跑的包，有的包可以只有mac头，但是不能只有ip头没有mac头。</p>
<p>MTU是二层的概念，也就是MAC头和正文不允许超过1500字节，如果放不下就需要分片处理。</p>
<h5 id="为什么不通过MAC地址直接定位机器？"><a href="#为什么不通过MAC地址直接定位机器？" class="headerlink" title="为什么不通过MAC地址直接定位机器？"></a>为什么不通过MAC地址直接定位机器？</h5><p>因为ip有定位功能，mac就像身份证号，ip就像门牌号，通过身份证号询问找人难度很大。</p>
<h5 id="主机通讯"><a href="#主机通讯" class="headerlink" title="主机通讯"></a>主机通讯</h5><p>主机会先判断通讯的是否是同网段的，如果是同网段，发送arp请求，获得目的主机的mac地址，将本机mac地址和目的主机的mac地址填入MAC头，进行发送。</p>
<p>如果不是同网段，主机会将包发送到网关，将目的MAC地址填入网关的MAC地址。</p>
<h4 id="DHCP"><a href="#DHCP" class="headerlink" title="DHCP"></a>DHCP</h4><p>新加入的主机只知道自己的MAC地址，发送DHCP Discover，相当于吼一句我是新来的，MAC地址是xxxxxxxx，没有ip。</p>
<p>DHCP Discover：使用IP为0.0.0.0的地址发送一个广播，目的ip255.255.255.255，广播包封装UDP，UDP封装BOOTP。</p>
<h5 id="DHCP-Discover："><a href="#DHCP-Discover：" class="headerlink" title="DHCP Discover："></a>DHCP Discover：</h5><table>
<thead>
<tr>
<th align="center">mac头</th>
<th align="center">ip头</th>
<th align="center">UDP头</th>
<th align="center">BOOTP头</th>
<th align="center">正文</th>
</tr>
</thead>
<tbody><tr>
<td align="center">src本机mac<br />dst广播FFFFFFFF</td>
<td align="center">src0.0.0.0<br />dst广播255.255.255.255</td>
<td align="center">srcport:68<br />dstport:67</td>
<td align="center">boot request</td>
<td align="center">本机mac是这个，还没有ip地址</td>
</tr>
</tbody></table>
<h5 id="DHCP-Offer："><a href="#DHCP-Offer：" class="headerlink" title="DHCP Offer："></a>DHCP Offer：</h5><table>
<thead>
<tr>
<th align="center">mac头</th>
<th align="center">ip头</th>
<th align="center">UDP头</th>
<th align="center">BOOTP头</th>
<th align="center">正文</th>
</tr>
</thead>
<tbody><tr>
<td align="center">srcDHCP服务器mac<br />dst广播FFFFFFFF</td>
<td align="center">srcDHCP服务器IP<br />dst广播255.255.255.255</td>
<td align="center">srcport:67<br />dstport:68</td>
<td align="center">boot reply</td>
<td align="center">你mac是这个，分配ip给你</td>
</tr>
</tbody></table>
<h5 id="DHCP-request："><a href="#DHCP-request：" class="headerlink" title="DHCP request："></a>DHCP request：</h5><table>
<thead>
<tr>
<th align="center">mac头</th>
<th align="center">ip头</th>
<th align="center">UDP头</th>
<th align="center">BOOTP头</th>
<th align="center">正文</th>
</tr>
</thead>
<tbody><tr>
<td align="center">src本机mac<br />dst广播FFFFFFFF</td>
<td align="center">src0.0.0.0<br />dst广播255.255.255.255</td>
<td align="center">srcport:68<br />dstport:67</td>
<td align="center">boot request</td>
<td align="center">本机mac是这个，准备租用这个DHCP分配ip</td>
</tr>
</tbody></table>
<h5 id="DHCP-ACK："><a href="#DHCP-ACK：" class="headerlink" title="DHCP ACK："></a>DHCP ACK：</h5><table>
<thead>
<tr>
<th align="center">mac头</th>
<th align="center">ip头</th>
<th align="center">UDP头</th>
<th align="center">BOOTP头</th>
<th align="center">正文</th>
</tr>
</thead>
<tbody><tr>
<td align="center">srcDHCP服务器mac<br />dst广播FFFFFFFF</td>
<td align="center">srcDHCP服务器IP<br />dst广播255.255.255.255</td>
<td align="center">srcport:67<br />dstport:68</td>
<td align="center">boot reply</td>
<td align="center">DHCP ACK这个新人ip是在我这租用的</td>
</tr>
</tbody></table>
<h3 id="交换机与VLAN"><a href="#交换机与VLAN" class="headerlink" title="交换机与VLAN"></a>交换机与VLAN</h3><p>注意交换机有可能形成回路的，在实际的数据中心中，需要使用类似于STP协议等“比”出来一个根交换机以及子交换机的树状结构</p>
<p>VLAN是打标签，对于不同vlan的报文不进行转发。在二层头后面加一个12位的tag</p>
<h3 id="在Linux中常见的网络性能指标如下"><a href="#在Linux中常见的网络性能指标如下" class="headerlink" title="在Linux中常见的网络性能指标如下"></a>在Linux中常见的网络性能指标如下</h3><ul>
<li>带宽</li>
</ul>
<p>表示链路的最大传输速率，单位是b&#x2F;s 比特&#x2F;秒，在位服务器选网卡时，带宽就是最核心的参考指标，常用的带宽有1000M，10G，40G，100G等</p>
<p>网络带宽测试，测试的不是带宽，而是网络吞吐量，Linux服务器的网络吞吐量一般会比带宽小，而对交换机等专门的网络设备来说，吞吐量一般会接近带宽</p>
<ul>
<li>吞吐量</li>
</ul>
<p>表示没有丢包时最大的数据传输速率，单位通常是b&#x2F;s比特&#x2F;秒，或B&#x2F;s字节&#x2F;秒，吞吐量受带宽的限制，吞吐量&#x2F;带宽也是该网络链路的使用率</p>
<ul>
<li>延迟</li>
</ul>
<p>表示从网络请求发出后，一直到收到远端响应所需要的时间延迟，这个指标在不同场景中有不同含义，它可以表示建立连接需要的时间(TCP握手延时)，或者一个数据包往返所需时间RTT</p>
<ul>
<li>PPS</li>
</ul>
<p>Packet Per Second，表示已网络包为单位的传输速率，PPS通常用来评估网络的转发能力，基于Linux服务器的转发，很容易受到网络包大小的影响(交换机通常不会受太大影响，交换机可以线性转发)</p>
<p>PPS，通常用在需要大量转发的场景中，而对TCP或者Web服务器来说，更多会用并发连接数和每秒请求数(QPS Query per Second)等指标，他们更能反映实际应用程序的性能</p>
<h4 id="理论上限"><a href="#理论上限" class="headerlink" title="理论上限"></a>理论上限</h4><p>672bit &#x3D; 8*(64B+20B)</p>
<p>百兆端口线速包转发率&#x3D;100Mbps&#x2F;672&#x3D;0.1488095Mpps，约等于0.14881Mpps，14万pps</p>
<p>千兆端口线速包转发率&#x3D;1000Mbps&#x2F;672&#x3D;1.488095Mpps，约等于1.4881Mpps，148万pps</p>
<p>万兆端口线速包转发率&#x3D;10000Mbps&#x2F;672&#x3D;14.88095Mpps，约等于14.881Mpps，1488万pps</p>
<h3 id="L2、L3"><a href="#L2、L3" class="headerlink" title="L2、L3"></a>L2、L3</h3><p>在Neutron里经常看到L2、L3层，那么L2、L3是什么？</p>
<p>L2：是七层网络的数据链路层，通过mac地址进行传输的，网卡驱动程序。</p>
<p>L3：是七层网络中的网络层，通过ip地址进行传输数据，典型协议是ip协议，icmp协议等。解决的是不同网段之间的网络</p>
<p>通信问题，主要就是选择路由，选择到达目标主机的最优路径</p>
<h3 id="数据链路层"><a href="#数据链路层" class="headerlink" title="数据链路层"></a>数据链路层</h3><p>这一层和数据的包结构和字段打交道，一方面接受来自网络层的数据帧，并且暴漏tcp Header给交换机等设备；另一方面他接受来自设备或者交换机、网桥的数据封装 tcp Header传输给网络层。</p>
<p>数据链路层由IEEE802规划改进为包含两个子层：介质访问控制（MAC）和逻辑链路控制（LLC）。<br>智能集线器、网桥和网络接口卡（NIC）等就驻扎在这一层。但是网络接口卡它同样具有物理层的一些编码功能等。</p>
<h3 id="网络层"><a href="#网络层" class="headerlink" title="网络层"></a>网络层</h3><p>这一层干的事就比较多了。它工作对象，概括的说就是：电路、数据包和信息交换。 </p>
<p>网络层确定把数据包通过网络发送到目的设备，就是把逻辑网络地址转换为物理地址。如果数据包太大不能通过路径中的一条链路送到目的地，那么网络层的任务就是把这些包分成较小的包。</p>
<p>这些任务就由路由、网桥路由、网关等设备完成。</p>
<h3 id="其他层"><a href="#其他层" class="headerlink" title="其他层"></a>其他层</h3><h4 id="第一层，物理层"><a href="#第一层，物理层" class="headerlink" title="第一层，物理层"></a>第一层，物理层</h4><p>OSI模型最低层的“劳苦大众”。它透明地传输比特流，就是传输的信号。该层上的设备包括集线器、发送器、接收器、电缆、连接器和中继器。 </p>
<h4 id="第四层，传输层"><a href="#第四层，传输层" class="headerlink" title="第四层，传输层"></a>第四层，传输层</h4><p>确保按顺序无错的发送数据包。传输层把来自会话层的大量消息分成易于管理的包以便向网络发送。 </p>
<h4 id="第五层，会话层"><a href="#第五层，会话层" class="headerlink" title="第五层，会话层"></a>第五层，会话层</h4><p>在分开的计算机上的两种应用程序之间建立一种虚拟链接，这种虚拟链接称为会话（session）。会话层通过在数据流中设置检查点而保持应用程序之间的同步。允许应用程序进行通信的名称识别和安全性的工作就由会话层完成。 </p>
<h4 id="第六层，表示层"><a href="#第六层，表示层" class="headerlink" title="第六层，表示层"></a>第六层，表示层</h4><p>定义由应用程序用来交换数据的格式。在这种意义上，表示层也称为转换器（translator）。该层负责协议转换、数据编码和数据压缩。转发程序在该层进行服务操作。 </p>
<h4 id="第七层，应用层"><a href="#第七层，应用层" class="headerlink" title="第七层，应用层"></a>第七层，应用层</h4><p>该层是OSI模型的最高层。应用层向应用进程展示所有的网络服务。当一个应用进程访问网络时，通过该层执行所有的动作。<br>纵观七层，从低级到高级。作一个形象的比喻就是从汇编到了BASIC，越到高层与硬件的关联就越弱。</p>
<h3 id="物理介质：各个层在物理层面的载体"><a href="#物理介质：各个层在物理层面的载体" class="headerlink" title="物理介质：各个层在物理层面的载体"></a>物理介质：各个层在物理层面的载体</h3><p>物理层—-就是我们看得见的网卡。网卡的作用就是把线路发送过来的高频电流转化数据包，然后传给网卡驱动程序，同是也把网卡驱动程序传送过来的数据包转化成电信号传送出去。定义通过网络设备发送数据的物理方式：是网络媒介和设备间的接口。 </p>
<p>数据链路层—-是网卡驱动程序。定义控制通信连接的程序；封包；监测和改正包传输错误。 </p>
<p>网络层—-即NDIS，NDIS提供网络接口。决定网络设备间如何传输数据；根据唯一的网络设备地址选择包；提供流和拥塞控制，以阻止同时网络资源的损耗。 </p>
<p>传输层—-即TCP，TCP协议的封包处理是在这一层进行的。管理网络中首尾连接的信息传送；提供通过错误恢复和流控制装置传送可靠且有序的包；提供无连接面向包的传送。 </p>
<p>会话层—-即SPI，SPI是服务提供者接口，管理用户间的会话和对话；控制用户间的连接和挂断连接；报告上层错误。 </p>
<p>表示层—-API，它为应用程序提供接口。API负责SPI与应用程序之间的通信；定义不同体系间不同数据格式；具体说明独立结构的数据传输格式；编码和解码数据；加密和解密数据；压缩和解压缩数据。 </p>
<p>应用层—-EXE，就是大家常见的应用程序。定义用于网络通信和数据传输的用户接口程序；提供标准服务，比如虚拟终端、文档以及任务的传输和操作。 </p>
<h1 id="Linux虚拟网络基础"><a href="#Linux虚拟网络基础" class="headerlink" title="Linux虚拟网络基础"></a>Linux虚拟网络基础</h1><p>对于《深入理解OpenStack Neutron》这本书的今日理解：</p>
<p>Linux虚拟网络里面的设备跟我们通俗意义理解的设备并不一样，物理设备可能就是一个具有某些功能的物理实体。Linux虚拟网络里创建的设备就是一个结构体、驱动程序等。虚拟网络设备具有的一些功能可以理解为具有网桥、交换机、网卡功能的虚拟化，但是又不能直接把他们认为是网卡等设备，他们本质上是一个结构体，是一段函数定义，比如tap&#x2F;tun，定义完全一样，只是flag有区别，定义他们在二层还是在三层工作。</p>
<p><strong>tap、tun、veth pair在Linux中都被称为设备，在日常概念里，通常被称为接口。</strong></p>
<p><strong>反而是Bridge、Router这些在Linux中没有被称为设备的网络功能，在日常概念里被称为设备。</strong></p>
<h1 id="Neutron架构分析"><a href="#Neutron架构分析" class="headerlink" title="Neutron架构分析"></a>Neutron架构分析</h1><h2 id="Neutron的web-server框架"><a href="#Neutron的web-server框架" class="headerlink" title="Neutron的web server框架"></a>Neutron的web server框架</h2><p>采用pecan框架，遵循WSGI规范，参考《WSGI网关协议理解》</p>
<h2 id="Neutron的进程之间消息通信机制"><a href="#Neutron的进程之间消息通信机制" class="headerlink" title="Neutron的进程之间消息通信机制"></a>Neutron的进程之间消息通信机制</h2><p>AMQP标准，product和consumer的PRC调用机制，参考《thrift了解》</p>
<h2 id="Neutron的并发机制"><a href="#Neutron的并发机制" class="headerlink" title="Neutron的并发机制"></a>Neutron的并发机制</h2><p>Neutron使用Python编程，使用CPython解释器，一个进程内只能运行一个线程。</p>
<p>Neutron不属于”计算密集型应用“，属于”I&#x2F;O阻塞型应用“，不使用多进程而使用协程反而有一定的优势。</p>
<h4 id="协程概述"><a href="#协程概述" class="headerlink" title="协程概述"></a>协程概述</h4><p>协程不是进程，也不是线程，一个进程可以有多个线程，一个线程可以有多个协程，协程是用户态，不牵涉到内核态，可以认为它是一个可以挂起的函数，既然是函数就说明协程是串行的，也就是说不管有几核的cpu，都是使用单核运行多个协程</p>
<p>I&#x2F;O阻塞型是指相比于cpu的处理速度，当程序运行在I&#x2F;O相关程序时，cpu时空闲的，因此可以把函数挂起，处理其他的协程</p>
<p>当处理的I&#x2F;O程序比较多，属于”I&#x2F;O密集型“，使用协程无法应付，这时候采用”多进程+协程“</p>
<p>Neutron采用协程主要是使用yield和eventlet协程库</p>
<ul>
<li><p>yield：可以参考《Python总结一》</p>
</li>
<li><p>eventlet：是对使用yield这种主动的协程调度进行封装，对用户（应用程序）不可见，eventlet是对greenlet进行封装。</p>
<ul>
<li><p>greenlet</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">func1</span>():</span><br><span class="line">    <span class="built_in">print</span> (<span class="string">&quot;t1.1&quot;</span>)</span><br><span class="line">    gr2.switch()</span><br><span class="line">    <span class="built_in">print</span> (<span class="string">&quot;t1.2&quot;</span>)</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">func2</span>():</span><br><span class="line">    <span class="built_in">print</span> (<span class="string">&quot;t2.1&quot;</span>)</span><br><span class="line">    gr1.switch()</span><br><span class="line">    <span class="built_in">print</span> (<span class="string">&quot;t2.2&quot;</span>)</span><br><span class="line">gr1 = greenlet(func1) <span class="comment">#创建协程对象，func1在协程gr1里运行</span></span><br><span class="line">gr2 = greenlet(func2)</span><br><span class="line">gr1.switch()</span><br><span class="line"></span><br><span class="line"><span class="comment"># 协程对象被创建后并不会主动运行，需要成员函数switch（）去调度。</span></span><br><span class="line"><span class="comment"># gr1.switch()被调度，在协程对象1里执行函数func1，打印t1.1,执行gr2.switch()，func1被挂起，执行协程对象2里的func2，打印t2.1，在执行gr1.switch()，func1被调度，继续被挂起的地方执行，打印t1.2，执行完毕执行被挂起的协程对象gr2，打印t2.2，因此最终输出结果：</span></span><br><span class="line"><span class="comment"># t1.1 t2.1 t1.2 t2.2</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>eventlet：是对greenlet的封装，greenlet需要编程者去主动调度协程，eventlet不仅封装协程对象，还封装协程的切换（调度）。它还是一个网络处理方面的协程库，因为它是非阻塞型I&#x2F;O协程，当I&#x2F;O不发生阻塞时，他不会切到其他协程，只有网络I&#x2F;O发生阻塞，eventlet就会调度另一个协程，直到这个协程发生阻塞或者运行结束。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> eventlet</span><br><span class="line"><span class="keyword">import</span> time </span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">test</span>(<span class="params">s</span>):</span><br><span class="line">    <span class="built_in">print</span> (s+<span class="string">&quot;begin&quot;</span>)</span><br><span class="line">    time.sleep(<span class="number">1</span>)</span><br><span class="line">    <span class="built_in">print</span> (s+<span class="string">&quot;end&quot;</span>)</span><br><span class="line">    </span><br><span class="line">pool = eventlet.GreenPool(<span class="number">3</span>) <span class="comment">#起三个空的协程池，称为greenthread</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">3</span>):</span><br><span class="line">    pool.spawn(test(<span class="built_in">str</span>(i))) <span class="comment">#pool.spawn创建一个具体的协程，执行函数是test</span></span><br><span class="line">    </span><br><span class="line">---------</span><br><span class="line"><span class="number">0</span> begin</span><br><span class="line"><span class="number">0</span> end</span><br><span class="line"><span class="number">1</span> begin</span><br><span class="line"><span class="number">1</span> end</span><br><span class="line"><span class="number">2</span> begin</span><br><span class="line"><span class="number">2</span> end</span><br></pre></td></tr></table></figure></li>
</ul>
</li>
</ul>
<h2 id="neutron创建网络过程"><a href="#neutron创建网络过程" class="headerlink" title="neutron创建网络过程"></a>neutron创建网络过程</h2><ol>
<li>首先管理员拿到一组可以在互联网上寻址的 IP 地址，并且创建一个外部网络和子网。</li>
<li>租户创建一个网络和子网。</li>
<li>租户创建一个路由器并且连接租户子网和外部网络。</li>
<li>租户创建虚拟机。</li>
</ol>
<h2 id="OpenStack-网络类型"><a href="#OpenStack-网络类型" class="headerlink" title="OpenStack 网络类型"></a>OpenStack 网络类型</h2><ul>
<li>管理网络：用于 OpenStack 各组件之间的内部通信。</li>
<li>数据网络：用于云部署中虚拟数据之间的通信。</li>
<li>外部网络：公共网络，外部或 internet 可以访问的网络。</li>
<li>API 网络：暴露所有的 OpenStack APIs,包括 OpenStack 网络 API 给租户们。</li>
</ul>
<h2 id="Neutron网络基本概念"><a href="#Neutron网络基本概念" class="headerlink" title="Neutron网络基本概念"></a>Neutron网络基本概念</h2><p>Neutron管理的网络资源包括三个：network、subnet、port</p>
<ul>
<li><p><strong>network</strong></p>
<p>network是一个隔离的二级广播域，只在链路层广播。neutron支持的类型local，flat，vlan，vxlan和gre。</p>
<ul>
<li><strong>local</strong></li>
</ul>
<p>​       local是只与本机节点上同一网络的实例进行通讯，一般用于单机测试。</p>
<ul>
<li><p><strong>flat</strong></p>
<p>flat是无valn tagging的网络，可以与不同节点同一网络通讯。</p>
<p><font size=2>vlan taging是对于不同vlan n的标识，不同的vlan不能相互通讯，如果有交换机通过Trunk口进行通讯，则不同vlan可以通过tag可以识别哪一个vlan。这里flat就是一个没有Truck口的vlan。</font></p>
</li>
<li><p><strong>vlan</strong></p>
<p>vlan 网络是具有 802.1q tagging 的网络。</p>
<p>vlan 是一个二层的广播域，同一 vlan 中的 instance 可以通信，不同 vlan 只能通过 router 通信。</p>
<p>vlan 网络可跨节点，是应用最广泛的网络类型。</p>
</li>
<li><p><strong>vxlan</strong></p>
<p>vxlan 是基于隧道技术的 overlay 网络。</p>
<p>vxlan 网络通过唯一的 segmentation ID（也叫 VNI）与其他 vxlan 网络区分。</p>
<p>vxlan 中数据包会通过 VNI 封装成 UDP 包进行传输。</p>
<p>因为二层的包通过封装在三层传输，能够克服 vlan 和物理网络基础设施的限制。</p>
</li>
<li><p><strong>gre</strong></p>
<p>gre 是与 vxlan 类似的一种 overlay 网络。</p>
<p>主要区别在于使用 IP 包而非 UDP 进行封装。</p>
</li>
</ul>
<p>不同 network 之间在二层上是隔离的。</p>
</li>
</ul>
<p>​		以 vlan 网络为例：</p>
<p>​		network A 和 network B 会分配不同的 VLAN ID，这样就保证了 network A 中的广播包不会跑到 network B 中。</p>
<p>​		当然，这里的隔离是指二层上的隔离，借助路由器不同 network 是可能在三层上通信的。</p>
<p>​		network 必须属于某个 Project（ Tenant 租户），Project 中可以创建多个 network。</p>
<p>​		Project 与 network 之间是 1对多关系。</p>
<ul>
<li><p><strong>subnet</strong></p>
<p>subnet 是一个 IPv4 或者 IPv6 地址段。</p>
<p>instance 的 IP 从 subnet 中分配。</p>
<p>每个 subnet 需要定义 IP 地址的范围和掩码。</p>
<p>network 与 subnet 是 1对多 关系。</p>
<p>一个 subnet 只能属于某个 network；一个 network 可以有多个 subnet，这些 subnet 可以是不同的 IP 段，但不能重叠。</p>
<p>下面的配置是有效的：</p>
<p>network A  subnet A-a: 10.10.1.0&#x2F;24 {“start”: “10.10.1.1”, “end”: “10.10.1.50”}</p>
<p>​          subnet A-b: 10.10.2.0&#x2F;24 {“start”: “10.10.2.1”, “end”: “10.10.2.50”}</p>
<p>但下面的配置则无效，因为 subnet 有重叠</p>
<p>network A  subnet A-a: 10.10.1.0&#x2F;24 {“start”: “10.10.1.1”, “end”: “10.10.1.50”}</p>
<p>​       subnet A-b: 10.10.1.0&#x2F;24 {“start”: “10.10.1.51”, “end”: “10.10.1.100”}</p>
<p>这里不是判断 IP 是否有重叠，而是 subnet 的 CIDR 重叠（都是 10.10.1.0&#x2F;24）。</p>
<p>但是，如果 subnet 在不同的 network 中，CIDR 和 IP 都是可以重叠的，比如</p>
<p>network A  subnet A-a: 10.10.1.0&#x2F;24 {“start”: “10.10.1.1”, “end”: “10.10.1.50”}</p>
<p>networkB  subnet B-a: 10.10.1.0&#x2F;24 {“start”: “10.10.1.1”, “end”: “10.10.1.50”}</p>
<p>如果上面的IP地址是可以重叠的，那么就可能存在具有相同 IP 的两个 instance，这样并不会冲突。</p>
<p>具体原因：</p>
<p>因为 Neutron 的 router 是通过 Linux network namespace 实现的。</p>
<p>network namespace 是一种网络的隔离机制。</p>
<p>通过它，每个 router 有自己独立的路由表。</p>
<p>上面的配置有两种结果：</p>
<p>如果两个 subnet 是通过同一个 router 路由，根据 router 的配置，只有指定的一个 subnet 可被路由。</p>
<p>如果上面的两个 subnet 是通过不同 router 路由，因为 router 的路由表是独立的，所以两个 subnet 都可以被路由。</p>
</li>
<li><p><strong>port</strong></p>
<p>port 可以看做虚拟交换机上的一个端口。</p>
<p>port 上定义了 MAC 地址和 IP 地址，当 instance 的虚拟网卡 VIF（Virtual Interface） 绑定到 port 时，port 会将 MAC 和 IP 分配给 VIF。</p>
<p>subnet 与 port 是 1对多 的关系：</p>
<p>一个 port 必须属于某个 subnet；</p>
<p>一个 subnet 可以有多个 port。</p>
</li>
<li><p><strong>小节</strong></p>
<p>下面总结了 Project，Network，Subnet，Port 和 VIF 之间关系。</p>
<p>Project 1 : m Network</p>
<p>Network 1 : m Subnet</p>
<p>Subnet 1 : m Port</p>
<p>Port 1 : 1 VIF</p>
<p>VIF m : 1 Instance</p>
</li>
</ul>
<hr>
<p><strong>Neutron</strong> <strong>架构</strong></p>
<p>与 OpenStack 的其他服务的设计思路一样，Neutron 也是采用分布式架构，由多个组件（子服务）共同对外提供网络服务。</p>
<p>Neutron 由如下组件构成：</p>
<p><strong>Neutron Server</strong></p>
<p>　　对外提供 OpenStack 网络 API，接收请求，并调用 Plugin 处理请求。</p>
<p><strong>Plugin</strong></p>
<p>　　处理 Neutron Server 发来的请求，维护 OpenStack 逻辑网络状态， 并调用 Agent 处理请求。</p>
<p><strong>Agent</strong></p>
<p>　　处理 Plugin 的请求，负责在 network provider 上真正实现各种网络功能。</p>
<p><strong>network provider</strong></p>
<p>　　提供网络服务的虚拟或物理网络设备，例如 Linux Bridge，Open vSwitch 或者其他支持 Neutron 的物理交换机。</p>
<p><strong>Queue</strong></p>
<p>　　Neutron Server，Plugin 和 Agent 之间通过 Messaging Queue 通信和调用。</p>
<p><strong>Database</strong></p>
<p>　　存放 OpenStack 的网络状态信息，包括 Network, Subnet, Port, Router 等。</p>
<p>Neutron 架构非常灵活，层次较多，目的是：</p>
<p>为了支持各种现有或者将来会出现的优秀网络技术。</p>
<p>支持分布式部署，获得足够的扩展性。</p>
<p>以创建一个 VLAN100 的 network 为例，假设 network provider 是 linux bridge， 流程如下：</p>
<ul>
<li>Neutron Server 接收到创建 network 的请求，通过 Message Queue（RabbitMQ）通知已注册的 Linux Bridge Plugin。</li>
<li>Plugin 将要创建的 network 的信息（例如名称、VLAN ID等）保存到数据库中，并通过 Message Queue 通知运行在各节点上的 Agent。</li>
<li>Agent 收到消息后会在节点上的物理网卡（比如 eth2）上创建 VLAN 设备（比如 eth2.100），并创建 bridge （比如 brqXXX） 桥接 VLAN 设备。</li>
</ul>
<hr>
<p><strong>ML2</strong></p>
<p>ML2 对二层网络进行抽象和建模，引入了 type driver 和 mechansim driver。</p>
<p><strong>Type Driver</strong></p>
<p>Neutron 支持的每一种网络类型都有一个对应的 ML2 type driver。</p>
<p>type driver 负责维护网络类型的状态，执行验证，创建网络等。</p>
<p>ML2 支持的网络类型包括 local, flat, vlan, vxlan 和 gre。</p>
<p><strong>Mechansim Driver</strong></p>
<p>Neutron 支持的每一种网络机制都有一个对应的 ML2 mechansim driver。</p>
<p>mechanism driver 负责获取由 type driver 维护的网络状态，并确保在相应的网络设备（物理或虚拟）上正确实现这些状态。</p>
<p>type 和 mechanisim 都太抽象，现在我们举一个具体的例子：</p>
<p><font color=blue>type driver 为 vlan，mechansim driver 为 linux bridge</font></p>
<p><font color=blue>我们要完成的操作是创建 network vlan100，那么：vlan type driver 会确保将 vlan100 的信息保存到 Neutron 数据库中，包括 network 的名称，vlan ID 等。</font></p>
<p><font color=blue>linux bridge mechanism driver 会确保各节点上的 linux brige agent 在物理网卡上创建 ID 为 100 的 vlan 设备 和 brige 设备，并将两者进行桥接。</font></p>
<p>mechanism driver 有三种类型：</p>
<p><strong>Agent-based</strong></p>
<p>包括 linux bridge, open vswitch 等。</p>
<p><strong>Controller-based</strong></p>
<p>包括 OpenDaylight, VMWare NSX 等。</p>
<p><strong>基于物理交换机</strong></p>
<p>包括 Cisco Nexus, Arista, Mellanox 等。</p>
<p>比如前面那个例子如果换成 Cisco 的 mechanism driver，则会在 Cisco 物理交换机的指定 trunk 端口上添加 vlan100。</p>
<p>本章的 mechanism driver 将涉及 linux bridge, open vswitch 和 L2 population。</p>
<p>linux bridge 和 open vswitch 的 ML2 mechanism driver 作用是配置各节点上的虚拟交换机。</p>
<p>linux bridge driver 支持的 type 包括 local, flat, vlan, vxlan。</p>
<p>open vswitch driver 支持的 type 包括 local, flat, vlan, vxlan, gre。</p>
<p>L2 population driver 作用是优化和限制 overlay 网络中的广播流量。 vxlan 和 gre 都属于 overlay 网络。</p>
<p>ML2 core plugin 已经成为 OpenStack Neutron 的首选 plugin 。</p>
<hr>
<p>1、Neutron 通过 plugin 和 agent 提供的网络服务。</p>
<p>2、plugin 位于 Neutron server，包括 core plugin 和 service plugin。</p>
<p>3、agent 位于各个节点，负责实现网络服务。</p>
<p>4、core plugin 提供 L2 功能，ML2 是推荐的 plugin。</p>
<p>5、使用最广泛的 L2 agent 是 linux bridage 和 open vswitch。</p>
<p>6、service plugin 和 agent 提供扩展功能，包括 dhcp, routing, load balance, firewall, vpn 等。</p>
<p><img src="https://pic.downk.cc/item/5eb90decc2a9a83be512046f.png"></p>
<p>Neutron的ML2 plugin包含<strong>type driver</strong> 和<strong>mechanism driver</strong>，type driver决定了建立的网络类型，包括local、flat、vlan、vxlan、gre；mechanism driver决定了实现的技术，例如使用Linux bridge和ovs等。一个抽象驱动，一个建模驱动。</p>
<p>local只有同机同网络才能建立通讯；</p>
<p>flat不同机同网络可以通讯，一个虚机连一个网卡；</p>
<p>举例：</p>
<p>​		建立flat网络时，建立一个网桥和一个dhcp（subnet那里选择dhcp的话），当建立实例挂载在这个flat网络上时，同时建立网桥，dhcp tap，instance tap。</p>
<p><font size=2>tap：虚拟网络接口，用于连接虚机管理程序。个人理解一个tap&#x2F;tun从二层&#x2F;三层上定义一个虚拟网卡。</font> </p>
<p><strong>DHCP</strong></p>
<p>dhcp通过在控制节点&#x2F;网络节点的dhcp agent提供组件，默认通过dnsmasq程序实现dhcp功能。</p>
<p><img src="https://pic.downk.cc/item/5eba022bc2a9a83be5f85f76.jpg"></p>
<p>在dhcp配置参数里有一个 –interface  ，指定提供 DHCP 服务的 interface。dnsmasq 会在该 interface 上监听 instance 的 DHCP 请求。</p>
<p>Neutron 通过 dnsmasq 提供 DHCP 服务，而 dnsmasq 如何独立的为每个 network 服务呢？</p>
<p>通过 <strong>Linux Network Namespace</strong> 隔离</p>
<p>在二层网络上，VLAN 可以将一个物理交换机分割成几个独立的虚拟交换机。类似地，在三层网络上，Linux network namespace 可以将一个物理三层网络分割成几个独立的虚拟三层网络。</p>
<p>每个 namespace 都有自己独立的网络栈，包括 route table，firewall rule，network interface device 等。</p>
<p>Neutron 通过 namespace 为每个 network 提供独立的 DHCP 和路由服务，从而允许租户创建重叠的网络。如果没有 namespace，网络就不能重叠，这样就失去了很多灵活性。每个 dnsmasq 进程都位于独立的 namespace, 命名为 qdhcp-<network id></p>
<p>宿主机本身也有一个 namespace，叫 root namespace，拥有所有物理和虚拟 interface device。物理 interface 只能位于 root namespace。</p>
<p>新创建的 namespace 默认只有一个 loopback device。管理员可以将虚拟 interface，例如 bridge，tap 等设备添加到某个 namespace。</p>
<p>对于 flat_net 的 DHCP 设备 tap19a0ed3d-fe，需要将其放到 namespace qdhcp-f153b42f-c3a1-4b6c-8865-c09b5b2aa274 中，但这样会带来一个问题：tap19a0ed3d-fe 将无法直接与 root namespace 中的 bridge 设备 brqf153b42f-c3 连接。</p>
<p><strong>Neutron 使用 veth pair 解决了这个问题。</strong></p>
<p>veth pair 是一种成对出现的特殊网络设备，它们象一根虚拟的网线，可用于连接两个 namespace。向 veth pair 一端输入数据，在另一端就能读到此数据。</p>
<p>tap19a0ed3d-fe 与 ns-19a0ed3d-fe 就是一对 veth pair，它们将 qdhcp-f153b42f-c3a1-4b6c-8865-c09b5b2aa274 连接到 brqf153b42f-c3。</p>
<hr>
<p>以 cirros-vm1 为例分析获取 DHCP IP 的详细过程。</p>
<p>在创建 instance 时，Neutron 会为其分配一个 port，里面包含了 MAC 和 IP 地址信息。这些信息会同步更新到 dnsmasq 的 host 文件。同时 nova-compute 会设置 cirros-vm1 VIF 的 MAC 地址。</p>
<p>一切准备就绪，instance 获取 IP 的过程如下：</p>
<ol>
<li><p>cirros-vm1 开机启动，发出 DHCPDISCOVER 广播，该广播消息在整个 flat_net 中都可以被收到。</p>
</li>
<li><p>广播到达 veth tap19a0ed3d-fe，然后传送给 veth pair 的另一端 ns-19a0ed3d-fe。dnsmasq 在它上面监听，dnsmasq 检查其 host 文件，发现有对应项，于是dnsmasq 以  DHCPOFFER 消息将 IP（172.16.1.103）、子网掩码（255.255.255.0）、地址租用期限等信息发送给 cirros-vm1。</p>
</li>
<li><p>cirros-vm1 发送 DHCPREQUEST 消息确认接受此 DHCPOFFER。</p>
</li>
<li><p>dnsmasq 发送确认消息 DHCPACK，整个过程结束。</p>
</li>
</ol>
<p>这个过程我们可以在 dnsmasq 日志中查看。</p>
<p>dnsmasq 默认将日志记录到 &#x2F;var&#x2F;log&#x2F;syslog。</p>
<hr>
<p><strong>Routing 功能概述</strong></p>
<p>路由服务（Routing）提供跨 subnet 联通功能。例如前面我们搭建了<a target="_blank" rel="noopener" href="http://mp.weixin.qq.com/s?__biz=MzIwMTM5MjUwMg==&mid=2653587298&idx=1&sn=7ccef4b40e40edea6f1d45b87930a42e&chksm=8d308f7bba47066db7bcc6ba93b86adc2c9ab0b16a897411dd5f3094c411019f0235d260a905&scene=21#wechat_redirect">实验环境</a>：</p>
<p>cirros-vm1    172.16.100.3     vlan100</p>
<p>cirros-vm3    172.16.101.3     vlan101</p>
<p>这两个 instance 要通信必须借助 router。可以是物理 router 或者虚拟 router。</p>
<p><img src="https://pic.downk.cc/item/5eba1c11c2a9a83be525dde5.png"></p>
<p><strong>为什么要把 router_100_101 放到 namespace 中</strong>？</p>
<p>讨论一个深层次的问题：</p>
<p>为什么不直接在 tape17162c5-00 和 tapd568ba1a-74 上配置 Gateway IP，而是引入一个 namespace，在 namespace 里面配置 Gateway IP 呢？</p>
<p>首先考虑另外一个问题：</p>
<p>如果不用 namespace，直接 Gareway IP 配置到 tape17162c5-00 和 tapd568ba1a-74 上，能不能连通 subnet_172_16_100_0 和 subnet_172_16_101_0 呢？</p>
<p>答案是可以的，只要控制节点上配置了类似下面的路由。</p>
<blockquote>
<p>Destination Gateway Genmask Flags Metric Ref Iface</p>
<p>172.16.100.0 * 255.255.255.0 U 0 0  tapd568ba1a-74</p>
<p>172.16.101.0 * 255.255.255.0 U 0 0  tape17162c5-00</p>
</blockquote>
<p>既然不需要 namespace 也可以路由，为什么还要加一层 namespace 增加复杂性呢？</p>
<p>其根本原因是：<strong>为了支持网络重叠</strong>。</p>
<p>云环境下，租户可以按照自己的规划创建网络，不同租户的网络是可能重叠的。将路由功能放到 namespace 中，就能隔离不同租户的网络，从而支持网络重叠。</p>
<p>下面通过例子进一步解释。</p>
<blockquote>
<p>Tenant A  vlan100 subnet A-1: 10.10.1.0&#x2F;24   {“start”: “10.10.1.1”, “end”: “10.10.1.254”}</p>
<p>Tenant A  vlan101 subnet A-2: 10.10.2.0&#x2F;24   {“start”: “10.10.2.1”, “end”: “10.10.2.254”}</p>
<p>Tenant B  vlan102 subnet B-1: 10.10.1.0&#x2F;24   {“start”: “10.10.1.1”, “end”: “10.10.1.254”}</p>
<p>Tenant B  vlan103 subnet B-2: 10.10.2.0&#x2F;24   {“start”: “10.10.2.1”, “end”: “10.10.2.254”}</p>
</blockquote>
<p>A，B 两个租户定义了完全相同的两个 subnet，网络完全重叠。</p>
<p>其特征是网关 IP 配置在 TAP interface 上。因为没有 namespace 隔离，router_100_101 和 router_102_103 的路由条目都只能记录到控制节点操作系统（root namespace）的路由表中，内容如下：</p>
<blockquote>
<p>Destination Gateway Genmask Flags Metric Use Iface</p>
<p> 10.10.1.0  * 255.255.255.0  U   0    0    tap1</p>
<p> 10.10.2.0  * 255.255.255.0  U   0    0    tap2</p>
<p> 10.10.1.0  * 255.255.255.0  U   0    0    tap3</p>
<p> 10.10.2.0  * 255.255.255.0  U   0    0    tap4</p>
</blockquote>
<p>这样的路由表是无法工作的。</p>
<p>按照路由表优先匹配原则，Tenant B 的数据包总是错误地被 Tenant A 的 router 路由。例如 vlan102 上有数据包要发到 vlan103。选择路由时，会匹配路由表的第二个条目，结果数据被错误地发到了 vlan101。</p>
<p><strong>使用 namespace 的场景</strong></p>
<p>其特征是网关 IP 配置在 namespace 中的 veth interface 上。每个 namespace 拥有自己的路由表。</p>
<p>router_100_101 的路由表内容如下：</p>
<blockquote>
<p>Destination Gateway Genmask Flags Metric Use Iface</p>
<p>10.10.1.0 * 255.255.255.0  U   0    0   qr-1</p>
<p>10.10.2.0 * 255.255.255.0  U   0    0   qr-2</p>
</blockquote>
<p>router_102_103 的路由表内容如下：</p>
<blockquote>
<p>Destination Gateway Genmask Flags Metric Use Iface</p>
<p>10.10.1.0 * 255.255.255.0  U   0    0   qr-3</p>
<p>10.10.2.0 * 255.255.255.0  U   0    0   qr-4</p>
</blockquote>
<p>这样的路由表是可以工作的。</p>
<p>例如 vlan102 上有数据包要发到 vlan103。选择路由时，会查看 router_102_103 的路由表, 匹配第二个条目，数据通过 qr-4 </p>
<p>被正确地发送到 vlan103。</p>
<p>同样当 vlan100 上有数据包要发到 vlan101时，会匹配 router_100_101 路由表的第二个条目，数据通过 qr-2 被正确地发送到 vlan101。</p>
<p>可见，namespace 使得每个 router 有自己的路由表，而且不会与其他 router 冲突，所以能很好地支持网络重叠。</p>
<p>建立外部网络，伴随生成一个网桥br，外部网络网卡接到这个网桥上。</p>
<p>router 的每个 interface 在 namespace 中都有对应的 veth。如果 veth 用于连接租户网络，命名格式为 qr-xxx，比如 qr-d568ba1a-74 和 qr-e17162c5-00。如果 veth 用于连接外部网络，命名格式为 qg-xxx，比如 qg-b8b32a88-03。</p>
<p><img src="https://pic.downk.cc/item/5eba4774c2a9a83be57d8526.png"><br>当租户网络连接到 Neutron router，通常将 router 作为默认网关。当 router 接收到 instance 的数据包，并将其转发到外网时:</p>
<ol>
<li><p>router 会修改包的源地址为自己的外网地址，这样确保数据包转发到外网，并能够从外网返回。</p>
</li>
<li><p>router 修改返回的数据包，并转发给真正的 instance。</p>
</li>
</ol>
<p>这个行为被称作 <a target="_blank" rel="noopener" href="http://mp.weixin.qq.com/s?__biz=MzIwMTM5MjUwMg==&mid=2653587316&idx=1&sn=114abfc48e6984309507e523d1548cad&chksm=8d308f6dba47067b5b206331fdbc2391dc508e50697ea26a4012e11763d391dc1f3e1117ff13&scene=21#wechat_redirect">Source NAT</a>。</p>
<p>如果需要从外网直接访问 instance，则可以利用 floating IP。下面是关于 floating IP 必须知道的事实：</p>
<ol>
<li><p>floating IP 提供静态 NAT 功能，建立外网 IP 与 instance 租户网络 IP 的一对一映射。</p>
</li>
<li><p>floating IP 是配置在 router 提供网关的外网 interface 上的，而非 instance 中。</p>
</li>
<li><p>router 会根据通信的方向修改数据包的源或者目的地址。</p>
</li>
</ol>
<ul>
<li><p>floating IP 能够让外网直接访问租户网络中的 instance。这是通过在 router 上应用 iptables 的 NAT 规则实现的。</p>
</li>
<li><p>floating IP 是配置在 router 的外网 interface 上的，而非 instance，这一点需要特别注意。</p>
</li>
</ul>
<p><strong>vxlan</strong> 和 <strong>gre</strong> 两种 overlay network</p>
<p>overlay network 是指建立在其他网络上的网络。overlay network 中的节点可以看作通过虚拟（或逻辑）链路连接起来的。overlay network 在底层可能由若干物理链路组成，但对于节点，不需要关心这些底层实现。</p>
<p>例如 P2P 网络就是 overlay network，隧道也是。vxlan 和 gre 都是基于隧道技术实现的，它们也都是 overlay network。</p>
<p>目前 linux bridge 只支持 vxlan，不支持 gre；open vswitch 两者都支持。vxlan 与 gre 实现非常类似，而且 vxlan 用得较多。</p>
<p>VXLAN 为 Virtual eXtensible Local Area Network。正如名字所描述的，VXLAN 提供与 VLAN 相同的以太网二层服务，但拥有更强的扩展性和灵活性。与 VLAN 相比，VXLAN 有下面几个优势：</p>
<ol>
<li>支持更多的二层网段。</li>
</ol>
<p>VLAN 使用 12-bit 标记 VLAN ID，最多支持 4094 个 VLAN，这对大型云部署会成为瓶颈。VXLAN 的 ID （VNI 或者 VNID）则用 24-bit 标记，支持 16777216 个二层网段。</p>
<ol start="2">
<li>能更好地利用已有的网络路径。</li>
</ol>
<p>VLAN 使用 Spanning Tree Protocol 避免环路，这会导致有一半的网络路径被 block 掉。VXLAN 的数据包是封装到 UDP 通过三层传输和转发的，可以使用所有的路径。</p>
<ol start="3">
<li>避免物理交换机 MAC 表耗尽。</li>
</ol>
<p>由于采用隧道机制，TOR (Top on Rack) 交换机无需在 MAC 表中记录虚拟机的信息。</p>
<p>VXLAN 封装和包格式</p>
<p>VXLAN 是将二层建立在三层上的网络。通过将二层数据封装到 UDP 的方式来扩展数据中心的二层网段数量。</p>
<p>VXLAN 是一种在现有物理网络设施中支持大规模多租户网络环境的解决方案。VXLAN 的传输协议是 IP + UDP。</p>
<p>VXLAN 定义了一个 MAC-in-UDP 的封装格式。在原始的 Layer 2 网络包前加上 VXLAN header，然后放到 UDP 和 IP 包中。通过 MAC-in-UDP 封装，VXLAN 能够在 Layer 3 网络上建立起了一条 Layer 2 的隧道。</p>
<p>VXLAN 包的格式如下：</p>
<p><a target="_blank" rel="noopener" href="https://pic.downk.cc/item/5eba61d5c2a9a83be59c02f4.png"><img src="https://pic.downk.cc/item/5eba61d5c2a9a83be59c02f4.png"></a></p>
<p>​	</p>
<p>如上图所示，VXLAN 引入了 8-byte VXLAN header，其中 VNI 占 24-bit。VXLAN 和原始的 L2 frame 被封装到 UDP 包中。这 24-bit 的 VNI 用于标示不同的二层网段，能够支持 16777216 个 LAN。</p>
<p>VXLAN Tunnel Endpoint</p>
<p>VXLAN 使用 VXLAN tunnel endpoint (VTEP) 设备处理 VXLAN 的封装和解封。每个 VTEP 有一个 IP interface，配置了一个 IP 地址。VTEP 使用该 IP 封装 Layer 2 frame，并通过该 IP interface 传输和接收封装后的 VXLAN 数据包。</p>
<p>下面是 VTEP 的示意图：</p>
<p><a target="_blank" rel="noopener" href="https://pic.downk.cc/item/5eba6281c2a9a83be59cae39.png"><img src="https://pic.downk.cc/item/5eba6281c2a9a83be59cae39.png"></a></p>
<p><strong>VXLAN 包转发流程</strong></p>
<p>VXLAN 在 VTEP 间建立隧道，通过 Layer 3 网络传输封装后的 Layer 2 数据。下面例子演示了数据如何在 VXLAN 上传输：</p>
<p><a target="_blank" rel="noopener" href="https://pic.downk.cc/item/5eba6478c2a9a83be59e4845.png"><img src="https://pic.downk.cc/item/5eba6478c2a9a83be59e4845.png"></a></p>
<p>图中 Host-A 和 Host-B 位于 VNI 10 的 VXLAN，通过 VTEP-1 和 VTEP-2 之间建立的 VXLAN 隧道通信。数据传输过程如下：</p>
<ol>
<li><p>Host-A 向 Host-B 发送数据时，Host-B 的 MAC 和 IP 作为数据包的目标 MAC 和 IP，Host-A 的 MAC 作为数据包的源 MAC 和 IP，然后通过 VTEP-1 将数据发送出去。</p>
</li>
<li><p>VTEP-1 从自己维护的映射表中找到 MAC-B 对应的 VTEP-2，然后执行 VXLAN 封装，加上 VXLAN 头，UDP 头，以及外层 IP 和 MAC 头。此时的外层 IP 头，目标地址为 VTEP-2 的 IP，源地址为 VTEP-1 的 IP。同时由于下一跳是 Router-1，所以外层 MAC 头中目标地址为 Router-1 的 MAC。</p>
</li>
<li><p>数据包从 VTEP-1 发送出后，外部网络的路由器会依据外层 IP 头进行路由，最后到达与 VTEP-2 连接的路由器 Router-2。</p>
</li>
<li><p>Router-2 将数据包发送给 VTEP-2。VTEP-2 负责解封数据包，依次去掉外层 MAC 头，外层 IP 头，UDP 头 和 VXLAN 头。VTEP-2 依据目标 MAC 地址将数据包发送给 Host-B。</p>
</li>
</ol>
<p>上面的流程我们看到 VTEP 是 VXLAN 的最核心组件，负责数据的封装和解封。</p>
<p>隧道也是建立在 VTEP 之间的，VTEP 负责数据的传送。</p>
<p>**Linux 对 VXLAN 的支持<br>**<br>VTEP 可以由专有硬件来实现，也可以使用纯软件实现。目前比较成熟的 VTEP 软件实现包括：</p>
<ol>
<li>带 VXLAN 内核模块的 Linux</li>
<li>Open vSwitch<br>我们先来看 Linux 如何支持 VXLAN，Open vSwitch 方式将在后面讨论。<br><a target="_blank" rel="noopener" href="https://pic.downk.cc/item/5eba64dcc2a9a83be59e936d.png"><img src="https://pic.downk.cc/item/5eba64dcc2a9a83be59e936d.png"></a><br>实现方式：</li>
<li>Linux vxlan 创建一个 UDP Socket，默认在 8472 端口监听。</li>
<li>Linux vxlan 在 UDP socket 上接收到 vxlan 包后，解包，然后根据其中的 vxlan ID 将它转给某个 vxlan interface，然后再通过它所连接的 linux bridge 转给虚机。</li>
<li>Linux vxlan 在收到虚机发来的数据包后，将其封装为多播 UDP 包，从网卡发出。<br><a target="_blank" rel="noopener" href="https://mp.weixin.qq.com/s?__biz=MzIwMTM5MjUwMg==&mid=2653587527&idx=1&sn=5ce88aaf61a01a72388619c831f66a85&chksm=8d30805eba4709487a3554f6016498a4e249ade2bb3260c6b7b288cebf13e866080f43f0c3be&scene=21#wechat_redirect"><font size=5>实例</font></a><br><strong>Openvswitch(OVS)在Neutron里实现</strong><br><strong>控制节点</strong><br>**br-ex<br>**连接外部（external）网络的网桥。<br>**br-int<br>**集成（integration）网桥，所有 instance 的虚拟网卡和其他虚拟网络设备都将连接到该网桥。<br>**br-tun<br>**隧道（tunnel）网桥，基于隧道技术的 VxLAN 和 GRE 网络将使用该网桥进行通信。<br>这些网桥都是 Neutron 自动为我们创建的，但是通过 brctl show 命令却看不到它们。这是因为我们使用的是 Open vSwitch 而非 Linux Bridge，需要用 Open vSwitch 的命令 ovs-vsctl show 查看。<br><strong>计算节点</strong><br>计算节点上也有 br-int 和 br-tun，但没有 br-ext。这是合理的，因为发送到外网的流量是通过网络节点上的虚拟路由器转发出去的，所以 br-ext 只会放在网络节点（devstack-controller）上。</li>
</ol>
<hr>
<p>在 Open vSwitch 环境中，一个数据包从 instance 发送到物理网卡大致会经过下面几个类型的设备：<br><strong>tap interface</strong><br>命名为 tapXXXX。<br><strong>linux bridge</strong><br>命名为 qbrXXXX。<br><strong>veth pair</strong><br>命名为 qvbXXXX, qvoXXXX。<br><strong>OVS integration bridge</strong><br>命名为 br-int。<br><strong>OVS patch ports</strong><br>命名为 int-br-ethX 和 phy-br-ethX（X 为 interface 的序号）。<br><strong>OVS provider bridge</strong><br>命名为 br-ethX（X 为 interface 的序号）。<br><strong>物理 interface</strong><br>命名为 ethX（X 为 interface 的序号）。<br><strong>OVS tunnel bridge</strong><br>命名为 br-tun。<br>OVS provider bridge 会在 flat 和 vlan 网络中使用；OVS tunnel bridge 则会在 vxlan 和 gre 网络中使用。后面会通过实例详细讨论这些设备。<br>Open vSwitch 支持 local, flat, vlan, vxlan 和 gre 所有五种 network type。vxlan 和 gre 非常类似，</p>

        </div>

        
            <section class="post-copyright">
                
                    <p class="copyright-item">
                        <span>Author:</span>
                        <span>Ian Tang</span>
                    </p>
                
                
                    <p class="copyright-item">
                        <span>Permalink:</span>
                        <span><a href="https://tkhfree.github.io/2022/11/27/Neutron%E5%AD%A6%E4%B9%A0-2022-11-27/">https://tkhfree.github.io/2022/11/27/Neutron%E5%AD%A6%E4%B9%A0-2022-11-27/</a></span>
                    </p>
                
                
                    <p class="copyright-item">
                        <span>License:</span>
                        <span>Copyright (c) 2019 <a target="_blank" rel="noopener" href="http://creativecommons.org/licenses/by-nc/4.0/">CC-BY-NC-4.0</a> LICENSE</span>
                    </p>
                
                
                     <p class="copyright-item">
                         <span>Slogan:</span>
                         <span>Do you believe in <strong>DESTINY</strong>?</span>
                     </p>
                

            </section>
        
        <section class="post-tags">
            <div>
                <span>Tag(s):</span>
                <span class="tag">
                    
                    
                        <a href="/tags/openstack/"># openstack</a>
                    
                        <a href="/tags/python/"># python</a>
                    
                        
                </span>
            </div>
            <div>
                <a href="javascript:window.history.back();">back</a>
                <span>· </span>
                <a href="/">home</a>
            </div>
        </section>
        <section class="post-nav">
            
                <a class="prev" rel="prev" href="/2022/11/27/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%B3%BB%E7%BB%9F-2022-11-27/">计算机系统</a>
            
            
            <a class="next" rel="next" href="/2022/11/26/c_c++%E8%AF%AD%E6%B3%95%E4%BD%BF%E7%94%A8-2022-11-26/">c/c++语法使用</a>
            
        </section>


    </article>
</div>

            </div>
            <footer id="footer" class="footer">
    <div class="copyright">
        <span>© Ian Tang | Powered by <a href="https://hexo.io" target="_blank">Hexo</a> & <a href="https://github.com/Siricee/hexo-theme-Chic" target="_blank">Chic</a></span>
    </div>
</footer>

    </div>
</body>

</html>